Javascript之对象

简介

对象除了可以保持自有的属性,还可以从一个称为原型的对象继承属性
属性包括名字和值。属性名可以是包含空字符串在内的任意字符串,但对象中不能存在两个同名的属性

原型和原型链参考:Javascript之原型和原型链
对象继承参考:Javascript之对象继承

创建对象

可以使用对象字面量new 关键字ECMAScript 5 中的 Object.create() 函数来创建对象

// 对象字面量创建对象 // 推荐写法 var person = { name : "stone", age : 28 }; // 也可以写成 var person = {}; person.name = "stone"; person.age = 28; // new 关键字创建对象 var person = new Object(); person.name = "stone"; person.age = 28; // Object.create() 函数创建对象 var person = Object.create(Object.prototype); person.name = "stone"; person.age = 28; var obj1 = Object.create(null); console.log(obj1); // {}

使用new实例化对象会经历以下4个步骤

  • 创建一个新对象;
  • 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
  • 执行构造函数中的代码(为这个新对象添加属性);
  • 返回新对象:判断构造函数返回值是否为对象,如果为对象就使用构造函数返回的值,否则使用 obj,这样就实现了忽略构造函数返回的原始值。

模拟newObject.create方法参考:手写各种原生方法

属性

// 取值 // 推荐写法 console.log(person.name); // "stone" console.log(person.age); // "28" // 也可以写成 console.log(person["name"]); // stone console.log(person["age"]); // 28 // 赋值 // 推荐写法 person.name = "sophie"; // 赋值 person.age = 30; // 赋值 person.weight = 38; // 创建 // 也可以写成 person["name"] = "sophie"; // 赋值 person["age"] = 30; // 赋值 person["weight"] = 38; // 创建

方法

  • Object.getPrototypeOf(obj):获取对象构造函数的原型对象
  • Object.setPrototypeOf(obj, proto):设置对象的原型对象
  • Object.isExtensible(obj):对象是否可扩展(是否可以新增属性)
  • Object.seal(obj):冻结属性,不可以新增和删除,但可以修改现有的属性
  • Object.freeze(obj):冻结属性,不可以新增、删除和修改;不能修改该对象已有属性的可枚举性、可配置性、可写性;该对象的原型也不能被修改
  • Object.getOwnPropertyNames(obj):获取对象自有属性的属性名组成的数组
  • Object.getOwnPropertySymbols(obj):返回一个给定对象自身的所有 Symbol 属性的数组
  • Object.getOwnPropertyDescriptor(obj, key):返回指定对象上一个自有属性对应的属性描述符
  • Object.getOwnPropertyDescriptors(obj):获取一个对象的所有自身属性的描述符
  • Object.preventExtensions(obj):禁止扩展对象
  • Object.defineProperty(obj, key, { get() {}, set() {} , ...}):拦截对象操作
  • Object.defineProperties(obj, {}):批量设置对象属性
  • obj.hasOwnProperty(key):是否是对象自身属性
  • key in obj:对象自身或者原型链中是否有某个属性
  • delete obj.a:删除对象属性
  • for (let k in obj) {}:枚举
  • Object.keys(obj):对象属性的属性名组成的数组

delete 只是断开属性和宿主对象的联系,并没有真正的删除它
delete 运算符只能删除自有属性,不能删除继承属性

for...in 循环主要是为了遍历对象而生,不适用于遍历数组
for...of 循环可以用来遍历数组、类数组对象,字符串、SetMap 以及 Generator 对象

  • 检测属性可以通过in 运算符hasOwnPreperty()propertyIsEnumerable()
// in:若对象的自有属性或继承属性中包含这个属性则返回 true var o = { x: 1 } console.log("x" in o); // true,x是o的属性 console.log("y" in o); // false,y不是o的属性 console.log("toString" in o); // true,toString是继承属性 // hasOwnProperty():对象的自有属性 var o = { x: 1 } console.log(o.hasOwnProperty("x")); // true,x是o的自有属性 console.log(o.hasOwnProperty("y")); // false,y不是o的属性 console.log(o.hasOwnProperty("toString")); // false,toString是继承属性 // propertyIsEnumerable(): 对象的自有属性且这个属性的可枚举性 var o = Object.create({ y: 2 }); o.x = 1; o.propertyIsEnumerable("x"); // true:,x是o的自有属性,可枚举 o.propertyIsEnumerable("y"); // false,y是继承属性 Object.prototype.propertyIsEnumerable("toString"); // false,不可枚举 // !== 判断一个属性是否是 undefined(如果属性被显式的赋值成undefined,这种方法就不准了,需要用 in 检测) var o = { x: 1 } console.log(o.x !== undefined); // true,x是o的属性 console.log(o.y !== undefined); // false,y不是o的属性 console.log(o.toString !== undefined); // true,toString是继承属性
  • gettersetter
var o = { // 普通的数据属性 data_prop: value, // 存取器属性都是成对定义的函数 get accessor_prop() { /*这里是函数体 */ }, set accessor_prop(value) { /* 这里是函数体*/ } };

关卡

请实现下面用来枚举属性的对象工具函数:

/* * 把 p 中的可枚举属性复制到 o 中,并返回 o * 如果 o 和 p 中含有同名属性,则覆盖 o 中的属性 */ function extend(o, p) { for (prop in p) { // 遍历 p 中的所有属性 o[prop] = p[prop]; // 将属性添加至 o 中 } return o; }
/* * 将 p 中的可枚举属性复制至 o 中,并返回 o * 如果 o 和 p 中有同名的属性,o 中的属性将不受影响 */ function merge(o, p) { for (prop in p) { // 遍历 p 中的所有属性 if (o.hasOwnProperty[prop]) continue; // 过滤掉已经在 o 中存在的属性 o[prop] = p[prop]; // 将属性添加至 o 中 } return o; }
/* * 如果 o 中的属性在 p 中没有同名属性,则从 o 中删除这个属性 * 返回 o */ function restrict(o, p) { for (prop in o) { // 遍历 o 中的所有属性 if (! (prop in p)) delete o[prop]; // 如果在 p 中不存在,则删除之 } return o; }
/* * 如果 o 中的属性在 p 中存在同名属性,则从 o 中删除这个属性 * 返回 o */ function subtract(o, p) { for (prop in p) { // 遍历 p 中的所有属性 delete o[prop]; // 从 o 中删除(删除一个不存在的属性不会报错) } return o; }
/* * 返回一个新对象,这个对象同时拥有 o 的属性和 p 的属性 * 如果 o 和 p 中有重名属性,使用 p 中的属性值 */ function union(o, p) { return extend(extend({},o), p); }
/* * 返回一个新对象,这个对象拥有同时在 o 和 p 中出现的属性 * 很像求 o 和 p 的交集,但 p 中属性的值被忽略 */ function intersection(o, p) { return restrict(extend({},o), p); }
/* * 返回一个数组,这个数组包含的是 o 中可枚举的自有属性的名字 */ function keys(o) { if (typeof o !== "object") throw TypeError(); // 参数必须是对象 var result = []; // 将要返回的数组 for (var prop in o) { // 遍历所有可枚举的属性 if (o.hasOwnProperty(prop)) // 判断是否是自有属性 result.push(prop); // 将属性名添加至数组中 } return result; // 返回这个数组 }

创作不易,若本文对你有帮助,欢迎打赏支持作者!

 分享给好友: