对象(读书笔记)

300 阅读3分钟

对象属性的四大特性

对象的属性除了包含名字和值之外,属性还包含了写标识它们可写,可枚举和可配置的特性

ES5后,对于属性的三大特性,js提供对应的API。通过这些API给原型对象添加方法,并将它们设置成不可枚举的,这让它们看上去更像内置方法。

可以通过这些api给对象定义不能修改或删除的属性,借此封锁这个对象。

数据属性的4个特性分别是:

1.值(value)

2.可写性(writable)

3.可枚举性(enumerable)

4.可配置性(configurable)

存取器属性的4个特性

1.读取(get)

2.写入(set)

3.可枚举性(enumerable)

4.可配置性(configurable)

ES5定义了一个对象名为“属性描述符”(property descriptor)来代表对象属性的特性。数据属性的描述符对象的属性有value,writable,enumerable , configurable,存取器属性的描述符对象则用get和set属性代替value和writable。其中enumerable,configurable,writable是布尔值,set和get属性是函数值。

通过调用Object.getOwnPropertyDescriptior()可以获得某个对象特定属性的属性描述符。该API只能得到自由属性的描述符。要想获得对象集成对象属性的特性,需要遍历原型链(Object.getPrototypeOf()).若想设置属性的特性或者想让新建的属性具有某种特性,则需要调用Object.defineProperty()

Object.defineProperty(O,"x",{
                value:1, writable:true, enumerable:false, configurable:true
      })

属性的可枚举性和遍历 

可枚举性

对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。

let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
//  {
//    value: 123,
//    writable: true,
//    enumerable: true,
//    configurable: true
//  }

描述对象的enumerable属性,称为”可枚举性“,如果该属性为false,就表示某些操作会忽略当前属性。

目前,有四个操作会忽略enumerablefalse的属性。

  • for...in循环:只遍历对象自身的和继承的可枚举的属性。
  • Object.keys():返回对象自身的所有可枚举的属性的键名。
  • JSON.stringify():只串行化对象自身的可枚举的属性。
  • Object.assign(): 忽略enumerablefalse的属性,只拷贝对象自身的可枚举的属性。

这四个操作之中,前三个是 ES5 就有的,最后一个Object.assign()是 ES6 新增的。其中,只有for...in会返回继承的属性,其他三个方法都会忽略继承的属性,只处理对象自身的属性。实际上,引入“可枚举”(enumerable)这个概念的最初目的,就是让某些属性可以规避掉for...in操作,不然所有内部属性和方法都会被遍历到。比如,对象原型的toString方法,以及数组的length属性,就通过“可枚举性”,从而避免被for...in遍历到。

Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumerable
// false

Object.getOwnPropertyDescriptor([], 'length').enumerable
// false

上面代码中,toStringlength属性的enumerable都是false,因此for...in不会遍历到这两个继承自原型的属性。

另外,ES6 规定,所有 Class 的原型的方法都是不可枚举的。

Object.getOwnPropertyDescriptor(class {foo() {}}.prototype, 'foo').enumerable
// false

总的来说,操作中引入继承的属性会让问题复杂化,大多数时候,我们只关心对象自身的属性。所以,尽量不要用for...in循环,而用Object.keys()代替。