javascript--对象属性描述符

从ES5开始,JavaScript开始支持所有属性都具备属性描述符。

var myObject = {
    a: 2
};
Object.getOwnPropertyDescriptor(myObject, "a");
//{
//  value: 2
//  writable: true,
//  enumerable: true,
//  configurable: true
//}

这个普通的对象属性对应的属性描述符有四个:value、writable、enumerable、configurable,其中value标识属性值,其他三个用来描述属性是否可写、可枚举、可配置。
在创建属性时属性描述符会使用默认值,也可以通过使用Object.defineProperty()方法添加新属性或修改一个已有属性的描述符。

Object.defineProperty(myObject, "a", {
    value: 3,
    writable: true,
    configurable: true,
    enumerable: false
})
1、writable

writable决定是否可以修改属性的值。

var myObject = {};
Object.defineProperty(myObject, "a", {
    value: 2,
    writable: false,    // 不可写
    configurable: true,
    enumerable: true
});
myObject.a = 3; // 如果是严格模式,会抛出TypeError
myObject.a; // 2,修改属性a的值失败

javascript中Object.freeze()方法会创建一个冻结的对象,使对象的所有直接属性禁止修改,实际上该方法调用了Object.seal()方法,然后设置所有的对象直接属性的wriable:false。

2、configurable

configurable决定属性是否是可配置的,如果是可配置的,可以使用defineProperty()方法修改属性描述符。

var myObject = {
    a: 3
};

Object.defineProperty(myObject, "a", {
    value: 4,
    writable: true,
    configurable: false,    // 不可配置
    enumerable: true
});

delete myObject.a;  // 删除myObject.a
myObject.a; // 2  删除失败

// 再次调用defineProperty()方法会抛出TypeError错误
Object.defineProperty(myObject, "a", {
    value: 6,
    writable: true,
    configurable: true,
    enumerable: true
}); // TypeError

所以,一旦把属性的configurable修改为false就无法撤销,此操作是单向操作,并且该属性也无法被delete操作删除
javascript中有一个方法Object.seal(),会创建一个不能添加新属性,也不能重新配置或删除任何现有属性的“密封”对象。该方法实际上会调用Object.preventExtensions()方法,并把所有现有属性标记为configurable:false。其中Object.preventExtensions()方法会禁止向对象添加新属性且保留已有属性。

3、enumerable

enumerable控制属性是否会出现在对象的属性枚举中。比如for…in循环。如果设置为false,该属性就不会出现在枚举中。

var myObject = {};

Object.defineProperty(myObject, "a", {
    value: 2,
    enumerable: true

});

Object.defineProperty(myObject, "b", {
    value: 3,
    enumerable: false

});
myObject.b; // 3
("b" in myObject); // true
myObject.hasOwnProperty("b");   // true

for(var k in myObject) {
    console.log(k, myObject[k]);
}
// "a" 2

可以看到,myObject.b确实存在且有访问值,但却不会出现在for…in循环中。原因就是myObject.b的enumerable:false导致的。

4、对象常量

结合writable:false和configurable:false可以创建一个真正的常量属性。

var myObject = {}
Object.defineProperty(myObject, "CONSTANT", {
    value: 42,
    writable: false,
    configurable: false
});
5、Getter和Setter

在ES5中可以使用getter和setter改写属性的默认操作。getter和setter都是隐藏函数,getter会在获取属性值时调用,setter会在设置属性值时调用。
当给一个属性定义了getter、setter时,JavaScript会忽略他们的value和writable特性,取而代之的是get和set特性。

var myObject = {
    // 给a定义一个getter
    get a() {
        return 2;
    }
};

Object.defineProperty(myObject, "b", {
    get: function() {return this.a * 2},
    enumerable: ture
});

myObject.a; // 2
myObject.b; // 4

myObject.a = 3;
myObject.a; // 2

无论使用get a() {..}, 还是defineProperty()定义getter,二者都会在对象中创建一个不包含值的属性,对于该属性的访问会自动调用一个隐藏函数,该函数的返回值被当作属性访问的返回值。
由于没有为属性a定义setter,所以对属性a的赋值操作会失败。但是由于a属性的自定义getter只会返回2,所以即使定义了setter,赋值操作也是没有意义的。
接下来在看一个有合理setter和getter的对象属性:

var myObject = {
  get a() {
      return this._a_;
  },
  set a(val) {
      this._a_ = val * 2;
  }
};
myObject.a = 2;
myObject.a; // 4

猜你喜欢

转载自blog.csdn.net/Shie_3/article/details/81413319