js知識梳理2:對象屬性的操做

寫在前面

注:這個系列是本人對js知識的一些梳理,其中很多內容來自書籍:Javascript高級程序設計第三版和JavaScript權威指南第六版,感謝它們的做者和譯者。有發現什麼問題的,歡迎留言指出。數組

1.屬性的查詢和設置

①基本語法

這個簡單,能夠經過點(.)或方括號([])運算來獲取屬性的值,注意點運算符後的標識符不能是保留字,方括號內的表達式必須返回字符串或返回一個能夠轉換成字符串的值。this

var person = {
    name:'jaychou',
    height:172,
    sayName:function () {
        console.log(this.name);
    }
};
console.log(person['name']);
console.log(person.height);

每每有一些場景使用方括號比點語法更靈活:prototype

var addr = "";
for(var i=0;i<4;i++){
    //讀取customer對象的address0,address1,address2,address3屬性
    addr += customer["address"+i] + '\n';
}

②繼承相關的影響

原型鏈實現了屬性的繼承。簡單說,若是給對象o的屬性x賦值,若是o中已經有屬性x(自有屬性,不是繼承來的),那就會改變這個已有屬性x的值。若是o中不存在屬性x,那麼賦值操做給o添加一個新屬性x。若是以前o繼承了屬性x,那麼這個繼承的屬性就建立的同名屬性覆蓋了。固然,若是屬性的writable是false,就會拋出錯誤。設計

可是若是這個繼承來的屬性是具備setter方法的存取器屬性,這時會調用setter方法而不是給o建立一個屬性x。繼承來的屬性是隻讀的,纔會在o上建立屬性。code

③屬性訪問錯誤

查詢一個不存在的屬性不會報錯,返回undefined。但若是嘗試查詢這個不存在的對象它的屬性就會報錯。對象

給null和undefined設置屬性會報類型錯誤,嚴格模式下,設置屬性操做只要失敗都會拋出類型錯誤異常。繼承

2.刪除屬性

delete運算符能夠刪除對象的屬性,注意的是delete只是斷開屬性和宿主對象的聯繫,而不會去操做屬性中的屬性,並且爲了不內存泄漏,在銷燬對象的時候,要遍歷屬性中的屬性,依次刪除。ip

delete運算符只能刪除自有屬性(這是確定的,不然就影響了整個原型鏈的對象)。內存

3.檢測屬性

判斷某個屬性是否存在於某個對象中即爲檢測屬性,經常使用方法:in運算符、hasOwnProperty()、propertyIsEnumerable(),或者以前說起的屬性查詢也能夠。原型鏈

//in運算符:若是對象的自有屬性或繼承屬性中包含這個屬性則返回true:
var o = {x:1};
console.log("x" in o);//true:
console.log("y" in o);//false
console.log("toString" in o);//true:
//hasOwnProperty:檢測是不是對象的自有屬性
console.log(o.hasOwnProperty("x"));//true
console.log(o.hasOwnProperty("y"));//false
console.log(o.hasOwnProperty("toString"));//false
//propertyIsEnumerable:hasOwnProperty的加強版,是自有屬性且可枚舉
console.log(o.propertyIsEnumerable("x"));//true
console.log(Object.prototype.propertyIsEnumerable("toString"));//false:不可枚舉

其餘小辦法:!==判斷一個屬性是不是undefined(缺陷:!==沒法區分不存在的屬性和存在但值爲undefined的屬性)

console.log(o.x !== undefined);//true
console.log(o.y !== undefined);
console.log(o.toString !== undefined);//true

4.枚舉屬性

經常使用的遍歷對象屬性的方法(未包括ES6):for-in循環、Object.keys()、Object.getOwnPropertyNames()。

①for-in循環

for-in循環能夠遍歷對象中全部可枚舉的屬性(包括自有屬性和繼承屬性):

var o1 = {x:1,y:1,_z:111};
Object.defineProperty(o1,'sayX',{
    value:function () {
        console.log(this.x);
    },
    enumerable:false
});
Object.defineProperty(o1,'z',{
    get:function () { return this._z; },
    set:function (v) { this._z = v; },
    enumerable:false
})
//打印x,y,_z,不會打印sayX和z,由於其enumerable爲false
for(var p in o1) console.log(p);

②Object.keys()

返回一個數組,這個數組由對象中可枚舉的自有屬性的名稱組成。

//打印["x", "y", "_z"]
console.log(Object.keys(o1));

③Object.getOwnPropertyNames()

和Object.keys()相似,只是它返回對象的全部自有屬性的名稱,包括不可枚舉的。

//打印["x", "y", "_z", "sayX", "z"]
console.log(Object.getOwnPropertyNames(o1));
//打印["constructor", "__defineGetter__", "__defineSetter__", 
// "hasOwnProperty", "__lookupGetter__", "__lookupSetter__", 
// "isPrototypeOf", "propertyIsEnumerable", "toString", 
// "valueOf", "__proto__", "toLocaleString"]
console.log(Object.getOwnPropertyNames(Object.prototype));

④小拓展

給Object.prototype添加一個不可枚舉的extend()方法,這個方法將做爲參數傳入的對象的全部自有屬性(包括不可枚舉的)一一複製,除了值,也複製屬性的全部特性,除非在目標對象中存在同名的屬性。

Object.defineProperty(Object.prototype,'extend',{
   configurable:true,
   enumerable:false,//不可枚舉
   writable:true,
   value:function (o) {
       //先獲取o的所有自有屬性(包括不可枚舉的)
       var names = Object.getOwnPropertyNames(o);
       for(var i=0,len=names.length;i<len;i++){
           //若是屬性已經存在,跳過
           if(names[i] in this) continue;
           //獲取屬性的描述符
           var desc = Object.getOwnPropertyDescriptor(o,names[i]);
           //建立屬性到this
           Object.defineProperty(this,names[i],desc);
       }
    }
});

使用:
var emptyO = {_z:10};
//除了已有的屬性_z,其餘o1的全部屬性描述符都複製過去了
emptyO.extend(o1);
console.log(emptyO);
相關文章
相關標籤/搜索