屬性描述符

屬性描述符

在ES5開始,全部屬性都具有了屬性描述符。

咱們能夠經過Object.getOwnPropertyDescriptor來觀察到屬性的描述符,它是長這樣子的。app

Object.getOwnPropertyDescriptor({a: 1}, 'a');

// {
//   value: 1,
//   writable: true,
//   enumerable: true,
//   configurable: true
// }

writable決定該屬性是否只讀。
enumerable決定該屬性是否可枚舉。
configurable決定該屬性是否可從新設置描述符。this

屬性描述符的設置

當屬性的configurable爲true時,咱們能夠經過Object.defineProperty來修改屬性描述符。code

'use strict';

var foo = {a: 1};

for(var i in foo) {console.log(i)};
// 'a'

Object.defineProperty(foo, 'a', {
  writable: false,
  enumerable: false,
  configurable: false
});

foo.a = 2;// Uncaught TypeError: Cannot assign to read only property 'a' of object '#<Object>'

for(var i in foo) {console.log(i)};
// 'nothing happend'

Object.defineProperty(foo, 'a', { // Uncaught TypeError: Cannot redefine property: a
  configurable: true
});

訪問描述符(getter和setter)

getter和setter有兩種方式定義對象

字面量定義ip

var foo = {
  get a(){
    return this._a;
  },
  set a(value){
    this._a = value;
  }
};

使用Object.defineProperty定義原型鏈

var foo = {a: 1};

Object.defineProperty(
  foo,
  'a',
  {
    get(){
      return this._a;
    },
    set(value){
      this._a = value;
    }
  }
);

這個時候再看看屬性a的描述符。get

Object.getOwnPropertyDescriptor(foo, 'a')

// {
//   get: ƒ a(),
//   set: ƒ a(value),
//   enumerable: true,
//   configurable: true
// }

當出現gettersetter時,valuewritable就會失效。
此時,屬性a的描述符被稱爲訪問描述符
訪問描述符屬性描述符互斥,若是此時再從新設置value或者writable描述符,settergetter也會被丟棄。原型

屏蔽屬性

當你給一個對象賦值一個新的屬性 foo時,若是該對象的原型鏈上已存在屬性 foo,而且 foo被標記爲只讀( writable: false)時,嚴格模式下會拋出異常,非嚴格模式下,這條賦值語句會被忽略。這種屬性稱爲 屏蔽屬性

舉個例子it

'use strict';

var anotherObject = {};

Object.defineProperty(anotherObject, 'foo', {// 將anotherObject的foo屬性設爲只讀
  value: 1,
  writable: false
});

var myObject = Object.create(anotherObject);// 將myObject的原型設置爲anotherObject

console.log(myObject);// {}
console.log(myObject.foo);// 1

myObject.foo = 2;// Uncaught TypeError: Cannot assign to read only property 'a' of object '#<Object>'

還有一種狀況console

當你給一個對象賦值一個新的屬性 foo時,若是該對象的原型鏈上已存在屬性 foo,而且 foo被設置了 setter時,將會調用這個 setter,而且該賦值語句將會被忽略,此時也會發生屬性屏蔽。
var anotherObject = {};

Object.defineProperty(anotherObject, 'foo', {// 給anotherObject的foo屬性設置setter
  set(value) {
    console.log(value);
    this._foo = value;
  },
  get() {
    return this._foo;
  }
});

var myObject = Object.create(anotherObject);// 將myObject的原型設置爲anotherObject

myObject.foo = 2;// 此時會觸發anotherObject.foo的setter,控制檯輸出2

console.log(Object.hasOwnProperty(myObject, 'foo'));// false

解決方案

使用Object.defineProperty來添加屬性。

相關文章
相關標籤/搜索