一、知識儲備:
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); //<STRONG>Object {name: "zhangzhiying", lastAge: 21, sex: "女"}</STRONG> </script>
2、使用for in來循環遍歷原型對象的屬性,然後一一賦值給我們的空對象,從而實現了“繼承”。這個思路很正確,下面我們來對以上示例進行改造:
<script type="text/javascript"> var child={}; var mother={ name:"zhangzhiying", lastAge:21, <STRONG>set age(value){ this.lastAge=value; }, get age(){ return this.lastAge+1; },</STRONG> sex:"女" };<BR> <STRONG> mother.age=15;</STRONG> //有set方法,具有可寫性 function extend(target,source){ for(var p in source){ target[p]=source[p]; } return target; } extend(child,mother); console.log(child); //<STRONG>Object {name: "zhangzhiying", lastAge: 15, age: 16, sex: "女"}</STRONG> </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()方法確認一下<BR> console.log(Object.getO
<EM id=__mceDel></script> </EM>
結論:要實現繼承,我們還需要解決的問題->“繼承”屬性特性。
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; <SPAN style="COLOR: #333399"><STRONG>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; }</STRONG></SPAN> 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權威指南》,總結一點心得,有錯誤歡迎指正,共同學習進步~
以上這篇javascript 用函數實現繼承詳解就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持。