深刻探究JavaScript對象系列(二)

       上文中提到JavaScript對象是屬性的集合,本結就來談談對象的屬性以及對屬性的操做。我的認爲,JavaScript中對象的屬性比其餘語言複雜不少,因爲本屌的主業是PHP,所以當初看書時候也花了不少時間才把這部份內容給理清了。javascript

 

 

一.JavaScript屬性概述

       跟傳統的面向對象不太同樣,JavaScript對象是動態的,便可以隨時對一個js對象新增或刪除屬性,對屬性最多見的操做是設置、查找、刪除、檢測、枚舉。除此之外,每一個屬性還有一些與之相關的值,稱爲「屬性特性」:java

  • 可寫:代表該屬性是否能夠設置該屬性的值;
  • 可枚舉:代表是否能夠經過for/in循環返回該屬性;
  • 可配置:代表是否能夠刪除或建立該屬性。

       正是因爲上述3中屬性特性使得JavaScript中屬性相對其餘語言來講複雜了不少。此外,根據屬性的定義位置,能夠把屬性分爲:數組

  • 自有屬性:直接在對象中定義的屬性;
  • 繼承屬性:在對象的原型對象中定義的屬性。

 

 

二.對屬性的設置和查詢

      因爲對象的屬性一部分是由本身定義,還有一部分屬性是從原型對象那繼承下來,所以假如要查詢對象o中的屬性x時,若是o中不存在,js引擎將會陸續在o的原型對象中來尋找x,若是整條原型鏈中都找不到或者找到一個原型是null的對象,則返回undefined函數

var o = {};
o.x = 1;
p = inherit(o);  //建立一個新對象p,原型對象爲o,inherit函數請查看上一篇
console.log(p.x);  //返回1,因爲在對象p中找不到屬性x,則js引擎在它的原型對象中繼續查找

       如今假設給給對象o的屬性x賦值,若是o中以及有自有屬性x,則賦值操做值就直接改變該屬性的值,若是不存在,則賦值操做給o新增這個屬性x。若是o中的原型鏈中也有該屬性,則繼承的屬性就被這個新建立的屬性覆蓋了。this

       上述對屬性的賦值是基於一種理想狀況,事情每每不會那麼簡單,上面以及提到,每個屬性都有3個屬性特性:可寫、可枚舉、可設置,若是對象o中繼承了一個只讀屬性的x,則賦值操做是不被容許的。spa

        在JavaScript中,只有在查詢屬性時,才能體會到繼承的存在。code

 

 

三.刪除對象的屬性

       刪除一個JavaScript對象的屬性可使用delete運算符,然而須要注意的是:delete只是斷開屬性和宿主對象的聯繫,而不會去操做屬性中的屬性,在銷燬一個對象時應特別注意這點;此外delete只能刪除自有屬性,不能刪除繼承屬性,所以若是要刪除繼承屬性,須要先找到原型鏈中的該擁有該屬性的對象才能刪除它。對象

       若是碰到那種可配置性爲false的屬性,如經過變量聲明或函數聲明建立的全局的對象,是不能被刪除的,在嚴格模式下,刪除一個不可配置的屬性會報一個類型錯誤。blog

 

 

四.屬性的檢測和枚舉

       檢測一個屬性是否屬於某個對象有如下幾種方法:繼承

  • in運算符:若是對象的自有屬性或繼承屬性中有這個屬性則返回true;
  • hasOwnProperty():對象的這個方法用來檢測給定的名字是否是對象的自有屬性,對於繼承的屬性返回false;
  • propertyIsEnumerable():該方法是hasOwnProperty()方法的加強版,只有檢測到是自有屬性且該屬性是可枚舉的才返回true;
    var o ={};
    o.x = 1;
    p = inherit(o);
    p.y = 2;
    
    o.hasOwnProperty("x");   //返回true
    p.hasOwnProperty("x");   //返回false
    
    Object.property.propertyIsEnumerable("toString");   //返回false,toString()方法不可枚舉
    

     

       經過for/in循環能夠遍歷出對象中全部可枚舉的屬性(包括自有屬性和繼承屬性),通常來講,對象的內置方法是不可枚舉的,但在代碼中定義的屬性一般都是能夠枚舉,除非顯式地指定該屬性爲不可枚舉,例如:

var o ={x:1 , y:2, z:3};

o.propertyIsEnumerable("toString");  //返回false

for(p in o){
  console.log(p);
}          //循環輸出1,2,3,但不會輸出toString.

       在ECMAScript5中定義了兩個用於枚舉屬性名稱的函數Object.keys()和Object.getOwnPropertyNames(),前者返回一個由對象中可枚舉且自有屬性組成的數組,後者也返回一個數組,可是它返回的是自有屬性的名稱,無論其是否可枚舉,在ECMAScript3中能夠用如下方法來模擬前者:

1 function keys(o){
2     if(typeof o !== "object") throw TypeError();
3     var result = [];
4     for(prop in o){
5         if (!o.hasOwnProperty(prop)) continue;
6         else result.push(prop);
7     }
8     return result;
9 }

 

 

五.屬性getter和setter

       在ECMAScript5中,屬性值能夠用一個或兩個方法替代,這兩個方法就是getter和setter,由這兩個方法定義的屬性稱做「存取器屬性」,不一樣於「數據」屬性,它不具備寫屬性。

       若是一個存取器屬性同時具備getter和setter方法,則這個屬性是可讀寫的,若是隻有getter那麼它就是個只讀屬性;若是隻有setter方法,則是一個只寫屬性,讀取它時返回undefined

var o ={
    x : 2,
    y : 3,

    get z(){
        return this.x*this.y;
    },
    set z(value){
        this.x += value;
        this.y += value;
    }
};

console.log(o.z);   //返回6

o.z = 2;

console.log(o.z);      //返回20
相關文章
相關標籤/搜索