一、知識儲備: 1、枚舉屬性名稱的函數: (1)for...in:可以在迴圈體中遍歷對象中所有可枚舉的屬性(包括自有屬性和繼承屬性) (2)Object.keys():返回數組(可枚舉的自有屬性) (3)Object.getOwnPropertyNames():所有的自有屬性 3、屬性的特性:數據屬 ...
一、知識儲備:
1、枚舉屬性名稱的函數:
(1)for...in:可以在迴圈體中遍歷對象中所有可枚舉的屬性(包括自有屬性和繼承屬性)
(2)Object.keys():返回數組(可枚舉的自有屬性)
(3)Object.getOwnPropertyNames():所有的自有屬性
3、屬性的特性:數據屬性和存取器屬性
(1)數據屬性:可寫(writable) 可枚舉(enumerable) 可配置(configurable) 值(value)
數據屬性只有一個簡單的值;
(2)存取器屬性: 寫入(set) 讀取(get) 可枚舉(enumerable) 可配置(configurable)
存取器屬性不可寫(即沒有writable特性)。
屬性有set方法,那這個屬性是可寫的,有get方法,那這個屬性就是可讀的。
4、定義屬性特性的方法:Object.defineProperty(對象,屬性,描述符對象)
5、獲取屬性的描述符對象:Object.getOwnPropertyDescriptor(對象,屬性)
二、示例
1、根據for...in的用法,我們可以寫出模擬“繼承”的方法:
<script type="text/javascript"> var child={}; var mother={ name:"zhangzhiying", lastAge:21, sex:"女" }; function extend(target,source){ for(var p in source){ target[p]=source[p]; } return target; } extend(child,mother); console.log(child); //Object {name: "zhangzhiying", lastAge: 21, sex: "女"} </script>
2、使用for in來迴圈遍歷原型對象的屬性,然後一一賦值給我們的空對象,從而實現了“繼承”。這個思路很正確,下麵我們來對以上示例進行改造:
<script type="text/javascript"> var child={}; var mother={ name:"zhangzhiying", lastAge:21, set age(value){ this.lastAge=value; }, get age(){ return this.lastAge+1; }, sex:"女" };
mother.age=15; //有set方法,具有可寫性 function extend(target,source){ for(var p in source){ target[p]=source[p]; } return target; } extend(child,mother); console.log(child); //Object {name: "zhangzhiying", lastAge: 15, age: 16, sex: "女"} </script>
可以看到代碼中使用了一對set,get;其中age是一個存取器屬性。
運行的結果:一個不包含set,get的普通對象。
結論:for in實現的“繼承”不處理set和get ,它把存取器屬性(age)轉換為一個靜態的數據屬性。
3、給mother對象設置數據屬性
<script type="text/javascript"> var child={}; var mother={ name:"zhangzhiying", lastAge:21, set age(value){ this.lastAge=value; }, get age(){ return this.lastAge+1; }, sex:"女" }; Object.defineProperty(mother,"lastAge",{writable:false}); //把lastAge設置成了不可寫 mother.age=15; //設置無效,因為lastAge的值不變,所以lastAge+1不變,即age不變 function extend(target,source){ for(var p in source){ target[p]=source[p]; } return target; } extend(child,mother); console.log(child); //Object {name: "zhangzhiying", lastAge: 21, age: 22, sex: "女"} child.lastAge=12; //結果顯示lastAge改變,說明child.lastAge沒有“繼承”到mother.lastAge的特性,我們再用getOwnPropertyDesriptor()方法確認一下
console.log(Object.getOwnPropertyDescriptor(child,"lastAge")); //Object {value: 12, writable: true, enumerable: true, configurable: true}
console.log(child); //Object {name: "zhangzhiying", lastAge: 12, age: 22, sex: "女"}
</script>
結論:要實現繼承,我們還需要解決的問題->“繼承”屬性特性。
4、完善版本
<script type="text/javascript">
var child={};
var mother={
name:"zhangzhiying",
lastAge:21,
set age(value){
this.lastAge=value;
},
get age(){
return this.lastAge+1;
},
sex:"女"
};
Object.defineProperty(mother,"lastAge",{writable:false});
mother.age=15;
function extend(target,source){
var names=Object.getOwnPropertyNames(source); //獲取所有的屬性名
for(var i=0;i<names.length;i++){
if(names[i] in target) continue; //如果這個屬性存在,就跳過(原型繼承中,如果自有屬性和原型對象的屬性重名,保留自有屬性)
var desc=Object.getOwnPropertyDescriptor(source,names[i]); //獲取mother屬性的描述符對象(即屬性特性的集合,es5中用描述符對象來表示)
Object.defineProperty(target,names[i],desc); //將mother的描述符對象給child的屬性定義
}
return target;
}
extend(child,mother);
console.log(child);
child.lastAge=12;
console.log(Object.getOwnPropertyDescriptor(child,"lastAge"));
console.log(child);
</script>
最後的結果:
可以明顯看到三次的列印,child“繼承”到了set和get,lastAge數值沒發生變化,writable也是false了。
總結:最近在看《javascript權威指南》,總結一點心得,有錯誤歡迎指正,共同學習進步~