JavaScript 提供了一个内部数据结构,用来描述对象的属性,控制它的行为,比如该属性是否可写、可遍历等等。这个内部数据结构称为“属性描述对象”(attributes object)。每个属性都有自己对应的属性描述对象,保存该属性的一些元信息。下面是值为123属性描述对象的一个例子。 { value: 123, writable: false, enumerable: true, configurable: false } 咱们也可以通过访问器属性实现相同的目标,属性描述对象如下所示: { get: function () { return 123 }, enumerable: true, configurable: false } 3.1 使用属性描述符的函数 下面的函数允许咱们使用属性描述符: Object.defineProperty(obj, propName, propDesc):该方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。 obj:要在其上定义属性的对象。prop:要定义或修改的属性的名称。descriptor:将被定义或修改的属性描述符。 var obj = Object.defineProperty({}, “foo”, { value: 123, }) Object.defineProperties(obj, propDescObj): 该方法直接在一个对象上定义一个或多个新的属性或修改现有属性,并返回该对象。 obj: 将要被添加属性或修改属性的对象 props: 该对象的一个或多个键值对定义了将要为对象添加或修改的属性的具体配置 var obj = Object.defineProperties({}, { foo: { value: 123, enumerable: true }, bar: { value: “abc”, enumerable: true } }); Object.create(proto, propDescObj?): 方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。 proto:新创建对象的原型对象。propDescObj:可选。如果没有指定为 undefined,则是要添加到新创建对象的可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)对象的属性描述符以及相应的属性名称。这些属性对应Object.defineProperties()的第二个参数。 var obj = Object.create(Object.prototype, { foo: { value: 123, enumerable: true }, bar: { value: “abc”, enumerable: true } })
Object.getOwnPropertyDescriptor(obj, propName): 该方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性) obj:需要查找的目标对象prop:目标对象内属性名称 var o, d;
o = { get foo() { return 17; } }; d = Object.getOwnPropertyDescriptor(o, “foo”); // d { // configurable: true, // enumerable: true, // get: /the getter function/, // set: undefined // } 4.可枚举性(Enumerable) 本节说明哪些操作受可枚举性影响,哪些操作不受可见性影响。 下面,假设有以下定义: var proto = Object.defineProperties({}, { foo: { value: 1, enumerable: true }, bar: { value: 2, enumerable: false } })
var obj = Object.create(proto, { baz: { value: 1, enumerable: true }, gux: { value: 2, enumerable: false} }) 请注意,对象(包括proto)通常至少具有原型Object.prototype:
Object.getPrototypeOf({}) === Object.prototype true Object.prototype是定义标准方法(如toString和hasOwnProperty)的地方。 4.1 受可枚举性影响的操作 可枚举性仅影响两个操作:for-in循环和Object.keys()。 for-in循环遍历所有可枚举属性的名称,包括继承的属性(请注意,Object.prototype的所有非可枚举属性都不会显示): for (var x in obj) console.log(x); baz foo Object.keys() 返回所有自有(非继承)可枚举属性的名称: Object.keys(obj) [ ‘baz’ ] 如果需要所有属性的名称,则需要使用Object.getOwnPropertyNames()。 4.2 忽略可枚举性的操作 除了上述两个,其他操作都忽略了可枚举性,还有一些操作会考虑继承: “toString” in obj true obj.toString [Function: toString]
还有一些仅读取自有属性:
Object.getOwnPropertyNames(obj) [ ‘baz’, ‘qux’ ]
obj.hasOwnProperty(“qux”) true obj.hasOwnProperty(“toString”) false
Object.getOwnPropertyDescriptor(obj, “qux”) { value: 2, writable: false, enumerable: false, configurable: false } Object.getOwnPropertyDescriptor(obj, “toString”) undefined 创建,删除和定义属性仅影响原型链中的第一个对象: obj.propName = value obj[“propName”] = value
delete obj.propName delete obj[“propName”]
Object.defineProperty(obj, propName, desc) Object.defineProperties(obj, descObj)