1、知識儲備:javascript
一、枚舉屬性名稱的函數:java
(1)for...in:能夠在循環體中遍歷對象中全部可枚舉的屬性(包括自有屬性和繼承屬性)數組
(2)Object.keys():返回數組(可枚舉的自有屬性)函數
(3)Object.getOwnPropertyNames():全部的自有屬性學習
三、屬性的特性:數據屬性和存取器屬性this
(1)數據屬性:可寫(writable) 可枚舉(enumerable) 可配置(configurable) 值(value)es5
數據屬性只有一個簡單的值;spa
(2)存取器屬性: 寫入(set) 讀取(get) 可枚舉(enumerable) 可配置(configurable)對象
存取器屬性不可寫(即沒有writable特性)。blog
屬性有set方法,那這個屬性是可寫的,有get方法,那這個屬性就是可讀的。
四、定義屬性特性的方法:Object.defineProperty(對象,屬性,描述符對象)
五、獲取屬性的描述符對象:Object.getOwnPropertyDescriptor(對象,屬性)
2、示例
一、根據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>
二、使用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)轉換爲一個靜態的數據屬性。
三、給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>
結論:要實現繼承,咱們還須要解決的問題->「繼承」屬性特性。
四、完善版本
<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權威指南》,總結一點心得,有錯誤歡迎指正,共同窗習進步~