js知識梳理1:理解對象的屬性特性

1.數據屬性

數據屬性的4個特性:javascript

  • Configurable:①表示可否經過delete刪除屬性從而從新定義,②可否修改屬性的特性,③可否把屬性修改成訪問器屬性。對象直接量裏默認值true。
  • Enumerable:表示可否經過for-in循環返回屬性。對象直接量裏默認值true。
  • Writable:表示可否修改屬性的值。對象直接量裏默認值true。
  • Value:包含這個屬性的數據值。對象直接量裏默認值undefined。
//查看對象直接量的屬性的屬性特性默認值 var people = {  name:'jaychou',  sayName:function () { console.log(this.name); } }; /**{value: "jaychou", writable: true, enumerable: true, configurable: true}*/ console.log(Object.getOwnPropertyDescriptor(people,'name')); /**{value: ƒ, writable: true, enumerable: true, configurable: true}*/ console.log(Object.getOwnPropertyDescriptor(people,'sayName')); //getOwnPropertyDescriptor對於繼承屬性和不存在的屬性,返回undefined

要修改屬性默認的特性,使用Object.defineProperty()方法,接收3個參數:對象,屬性名字和描述符對象。java

//修改屬性默認特性: Object.defineProperty(person,'job',{ emumerable:false,//不可枚舉 value:'singer', writable:false,//不可寫 configurable:true }); /**{name: "jaychou", sayName: ƒ, job: "singer"}*/ console.log(person); for(var prop in person){ //打印name,sayName console.log(prop); } //會報錯 try{ person.job = 'director'; }catch (e) { //Cannot assign to read only property 'job' of object console.log(e); }

能夠屢次調用Object.defineProperty()方法修改同一個屬性,但在把configurable特性設置爲false以後就會有限制了:markdown

Object.defineProperty(person,'height',{ configurable:false,//不可配置 writable:true, value:172 }); try{ Object.defineProperty(person,'height',{ configurable:true,//出錯 enumerable:true,//出錯 value:175,//正常 writable:false,//writable從true變false能夠,false變true也會出錯 }); }catch (e) { //Cannot redefine property: height at Function.defineProperty console.log(e); } try{ delete person.height; }catch (e) { //設置成不可配置後也不可刪除:Cannot delete property 'height' of #<Object> console.log(e); }

另外,調用 Object.defineProperty()方法時,若是不指定,configurable、enumerable 和 writable 特性的默認值都是 false。若是是修改已有屬性,則無此限制。函數

2.存儲器屬性

存儲器屬性不包含數據值,只包含包含 getter 和 setter 函數(非必需)。 在讀取存儲器屬性時,會調用 getter 函數,這個函數負責返回有效的值;在寫入存儲器屬性時,會調用 setter 函數並傳入新值,這個函數負責決定如何處理數據。4個屬性特性以下:post

  • Configurable:①表示可否經過delete刪除屬性從而從新定義,②可否修改屬性的特性,③可否把屬性修改成數據屬性。對象直接量的默認值true
  • Enumerable:表示可否經過for-in循環返回屬性。對象直接量的默認值true
  • Get:在讀取屬性時調用的函數。對象直接量默認值undefined
  • Set:在寫入屬性時調用的函數。對象直接量的默認值undefined

定義存儲器屬性最簡單的方法是使用對象直接量語法的拓展寫法:ui

var p = { x:3.0, y:4.0, //r是可讀寫的存取器屬性 get r(){return Math.sqrt(this.x*this.x+this.y*this.y);}, set r(newValue){ var oldvalue = Math.sqrt(this.x*this.x+this.y*this.y); var ratio = newValue/oldvalue; this.x *= ratio; this.y *= ratio; }, //theta是隻讀存取器屬性 get theta(){return Math.atan2(this.y,this.x);} } console.log(p.r); p.r = 25;

使用Object.defineProperty()方法定義存儲器屬性:this

var book = { _year:2004, edition:1 }; Object.defineProperty(book,"year",{ get:function () { return this._year; }, set:function (newValue) { if(newValue>2004){ this._year = newValue; this.edition += newValue - 2004; } } }) /**{get: ƒ, set: ƒ, enumerable: false, configurable: false}*/ console.log(Object.getOwnPropertyDescriptor(book,'year'));

如例子所示,使用存儲器屬性的常見方式,即設置一個屬性的值會致使其餘屬性發生變化。還有一種常見就是如今流行的相似於Vue的響應式原理,就是把data中的屬性都使用defineProperty修改成存儲器屬性,能夠監聽到數據的變化。spa

3.定義多個屬性

常常要建立或修改多個屬性,這時候可使用Object.defineProperties()方法,它接收2個參數,要添加或修改屬性的對象和一個映射表,包含名稱和屬性描述符。code

var book1 = {}; Object.defineProperties(book1,{ _year:{ value:'2008' }, editor:{ enumerable:true, value:'2' }, year:{ get:function () { return this._year; }, set:function (newValue) { this._year = newValue; this.edition += newValue - 2004; } } });

4.對象的可擴展性

對象的可拓展性表示是否能夠給對象添加新屬性。全部內置對象和自定義對象都是顯式可擴展的,宿主對象的可擴展性是由Javascript引擎定義的。對象

1.查詢對象可拓展性
var teacher = {age:25}; //true:表明可拓展 console.log(Object.isExtensible(teacher));
2.轉換爲不可拓展(「鎖定對象」)
Object.preventExtensions(teacher); //false console.log(Object.isExtensible(teacher)); try{ teacher.subject = 'math'; }catch (e) { //TypeError: Cannot add property subject, object is not extensible console.log(e); }

轉換成不可拓展的操做是不可逆的,並且只能影響到對象自己的可拓展性,若是給一個不可拓展對象的原型添加屬性,這個不可拓展對象一樣會繼承這些新屬性。

5.密封對象

密封對象比鎖定對象更高一層,除了不可拓展之外,對象的全部自身屬性都設置成了不可配置的。一樣密封對象操做是不可逆的。

var tea1 = {subject:'math'}; //false:表明未密封 console.log(Object.isSealed(tea1)); Object.seal(tea1); try{ Object.defineProperty(tea1,'subject',{ //enumerable:false,//出錯 //configurable:true,//出錯 writable:false//和上面說的同樣,writable從true變成false能夠,false變成true則出錯 }); }catch (e) { console.log('出錯..'); console.log(e); } //true:已密封 console.log(Object.isSealed(tea1));

6.凍結對象

凍結比密封對象多的效果是:能夠將它自有的全部數據屬性設置爲只讀(若是對象的存取器屬性具備setter方法,存取器屬性將不受影響,仍能夠經過給屬性賦值調用它們)。

var tea2 = {subject:'Chinese'}; //false:表明未凍結 console.log(Object.isFrozen(tea2)); Object.freeze(tea2); try{ tea2.subject = 'math'; }catch (e) { //TypeError: Cannot assign to read only property 'subject' of object console.log(e); } //true:已凍結 console.log(Object.isFrozen(tea2));

7.屬性特性規則總結

  • 若是對象是不可拓展的,則能夠編輯已有的自有屬性,但不能給它添加新屬性。
  • 若是屬性是不可配置的,則不能修改它的可配置性和可枚舉性。
  • 若是存取器屬性是不可配置的,則不能修改其getter和setter方法,也不能將它轉換爲數據屬性。
  • 若是數據屬性是不可配置的,則不能將它轉換爲存取器屬性。
  • 若是數據屬性是不可配置的,則不能將它的可寫性從false修改成true,但能夠從true修改成false。
  • 若是數據屬性是不可配置且不可寫的,則不能修改它的值。然而可配置但不可寫屬性的值是能夠修改的(作法:先將它標記爲可寫的,而後修改它的值,最後轉換爲不可寫的)。
相關文章
相關標籤/搜索