foreverwaiting
万人非你X

一。对象的属性描述

JavaScript “属性描述对象”(attributes object

{

  value: 属性的属性值

  writable:是否可写

  enumerable:是否可遍历 比如for...in循环、Object.keys())跳过该属性

  configurable: 可配置性控制了属性描述对象的可写性

  get: undefined,取值函数(getter,默认为undefined

  set: undefined,存值函数(setter,默认为undefined

}

 

二。获取属性

1.  Object.getOwnPropertyDescriptor():获取指定属性的描述值(只能用于对象自身的属性,不能用于继承的属性

  参数:第一个参数是目标对象,第二个参数是一个字符串(对应目标对象的某个属性名),效果如下:

 

 

2.  Object.getOwnPropertyNames():方法返回一个数组,成员是参数对象自身的全部属性的属性名,不管该属性是否可遍历。【Object.keys只返回对象自身的可遍历属性的全部属性名】

 

 

  

3.  Object.defineProperty():允许通过属性描述对象,定义修改一个属性,然后返回修改后的对象。

  定义和修改🌰:如下定义一个对象obj,有一个p属性,定义p属性的writable为false,则可以看到修改p值后,并没有生效。【其次,当定义一个存在的属性时,即是修改了】

     

 

如果一次性定义或修改多个属性,可以使用Object.defineProperties()方法:如下

var obj = Object.defineProperties({}, {
  p1: { value: 123, enumerable: true },
  p2: { value: 'abc', enumerable: true },
  p3: { get: function () { return this.p1 + this.p2 },
    enumerable:true,
    configurable:true
  }
});

obj.p1 // 123
obj.p2 // "abc"
obj.p3 // "123abc"

 

4.  Object.prototype.propertyIsEnumerable():返回一个布尔值,用来判断某个属性是否可遍历。注意,这个方法只能用于判断对象自身的属性,对于继承的属性一律返回false

  

 

 

5.  对象的拷贝:hasOwnProperty那一行用来过滤掉继承的属性,否则可能会报错,因为Object.getOwnPropertyDescriptor读不到继承属性的属性描述对象。

 

var extend = function (to, from) {
  for (var property in from) {
    if (!from.hasOwnProperty(property)) continue;
    Object.defineProperty(
      to,
      property,
      Object.getOwnPropertyDescriptor(from, property)
    );
  }

  return to;
}

extend({}, { get a(){ return 1 } })
// { get a(){ return 1 } })

 

 

 

6.  对象冻结(控制对象状态):冻结对象的读写状态,防止对象被改变。

方案一:最强的Object.freeze。【无法添加新属性、无法删除旧属性、也无法改变属性的值,使得这个对象实际上变成了常量

  对应检查方法:Object.isFrozen

var obj = {
  p: 'hello'
};

Object.freeze(obj);

obj.p = 'world';
obj.p // "hello"

obj.t = 'hello';
obj.t // undefined

delete obj.p // false
obj.p // "hello"

 

方案二:其次的Object.seal。【无法添加新属性,也无法删除旧属性(可修改)】【实质是把属性描述对象的configurable属性设为false

  对应检查方法:Object.isSealed

var obj = {
  p: 'a'
};

// seal方法之前
Object.getOwnPropertyDescriptor(obj, 'p')
// Object {
//   value: "a",
//   writable: true,
//   enumerable: true,
//   configurable: true
// }

Object.seal(obj);

// seal方法之后
Object.getOwnPropertyDescriptor(obj, 'p')
// Object {
//   value: "a",
//   writable: true,
//   enumerable: true,
//   configurable: false
// }

Object.defineProperty(o, 'p', {
  enumerable: false
})
// TypeError: Cannot redefine property: p

 

方案三:最弱的Object.preventExtensions。【无法再添加新的属性

 

 

  对应检查方法:Object.preventExtensions

var obj = new Object();
Object.preventExtensions(obj);

Object.defineProperty(obj, 'p', {
  value: 'hello'
});
// TypeError: Cannot define property:p, object is not extensible.

obj.p = 1;
obj.p // undefined

 

上面的三个方法锁定对象的可写性有一个漏洞:

  1.  可以通过改变原型对象,来为对象增加属性。【除非obj的原型也冻结住

  2.  如果属性值是对象,上面这些方法只能冻结属性指向的对象,而不能冻结对象本身的内容。如下:

  

var obj = {
  foo: 1,
  bar: ['a', 'b']
};
Object.freeze(obj);
obj.bar.push('c');
obj.bar // ["a", "b", "c"]
上面代码中,obj.bar属性指向一个数组,obj对象被冻结以后,这个指向无法改变,即无法指向其他值,但是所指向的数组是可以改变的。

 

 

 

 

 

 

 

  

 

posted on 2020-04-26 17:02  foreverwaiting  阅读(953)  评论(0编辑  收藏  举报