大家好,我是IT修真院深圳分院第01期學員,一枚正直純潔善良的web程序員。
今天給大家分享一下,修真院官網JS(職業)任務4,深度思考中的知識點——JS原型鏈和訪問對象原型的方法
1.介紹
JavaScript 中,萬物皆對象。JavaScript根據"原型鏈"(prototype chain)模式,來實現繼承。
2.涉及
2.1對象
JavaScript中,對象是有區別的,分為普通對象和函數對象,Object ,Function 是JS自帶的函數對象,function定義方式本質上還是new Function方式。
function? f1(){};
var?f2?=?function(){};
var?f3?=?new?Function('str','console.log(str)');
var o3 = new f1();
var?o1?=?{};
var?o2?=new?Object();
console.log(typeof? Object); ?//function
console.log(typeof? Function); ?//function
console.log(typeof?o1);???//object
console.log(typeof?o2);???//object
console.log(typeof?o3);???//object
console.log(typeof? f1);???//function
console.log(typeof? f2);???//function
console.log(typeof ?f3);???//function
2.2對象繼承
Brendan Eich參考C++和Java,做了簡化設計,將new命令引入JavaScript中,new后面跟對象的構造函數,用來創建對象。這樣做有個缺點:無法共享方法和屬性。
比如,在DOG對象的構造函數中,設置一個實例對象的共有屬性species。
function DOG(name){
this.name = name;
this.species = '犬科';
}
然后,生成兩個實例對象:
var dogA = new DOG('大毛');
var dogB = new DOG('二毛');
這兩個對象的species屬性是獨立的,修改其中一個,不會影響到另一個。
dogA.species = '貓科';
alert(dogB.species); // 顯示"犬科",不受dogA的影響
每一個實例對象,都有自己的屬性和方法的副本。這不僅無法做到數據共享,也是極大的資源浪費。
Brendan Eich決定為構造函數設置一個prototype屬性。這個屬性包含一個對象,所有實例對象需要共享的屬性和方法,都放在這個對象里面;那些不需要共享的屬性和方法,就放在構造函數里面。實例對象一旦創建,將自動引用prototype對象的屬性和方法。也就是說,實例對象的屬性和方法,分成兩種,一種是本地的,另一種是引用的。
function DOG(name){
this.name = name;
}
DOG.prototype = { species : '犬科' };
var dogA = new DOG('大毛');
var dogB = new DOG('二毛');
alert(dogA.species); // 犬科
alert(dogB.species); // 犬科
species屬性放在prototype對象里,是兩個實例對象共享的。只要修改了prototype對象,就會同時影響到兩個實例對象。
DOG.prototype.species = '貓科';
alert(dogA.species); // 貓科
alert(dogB.species); // 貓科
由于所有的實例對象共享同一個prototype對象,那么從外界看起來,prototype對象就好像是實例對象的原型,而實例對象則好像"繼承"了prototype對象一樣。
2.3原型prototype
在JavaScript 中,每當定義一個對象(函數)時候,對象中都會包含一些預定義的屬性。其中函數對象的一個屬性就是原型對象 prototype。普通對象沒有prototype,但有__proto__屬性。
示例:
function? f1(){};
console.log(f1. prototype) //f1 {}
console.log(typeof ?f1. prototype) //object
console.log(typeof ?Function. prototype) // function
console.log(typeof ?Object. prototype) // object
console.log(typeof ?Function. prototype. prototype) //undefined
2.4 原型鏈
JS在創建對象(不論是普通對象還是函數對象)的時候,都有一個叫做__proto__的內置屬性,用于指向創建它的函數對象的原型對象prototype。
var person = function(name){
this.name = name
};
person.prototype.getName = function(){
return this.name;
}
var zjh = new person(‘zhangjiahao’);
zjh.getName(); //zhangjiahao
以上面的例子為例:
console.log(zjh.__proto__ === person.prototype) //true
同樣,person.prototype對象也有__proto__屬性,它指向創建它的函數對象(Object)的prototype
console.log(person.prototype.__proto__ === Object.prototype) //true
繼續,Object.prototype對象也有__proto__屬性,但它比較特殊,為null
console.log(Object.prototype.__proto__) //null
我們把這個有__proto__串起來的直到Object.prototype.__proto__為null的鏈叫做原型鏈。
2.5 constructor屬性
prototype對象有一個constructor屬性,默認指向prototype對象所在的構造函數。
由于constructor屬性定義在prototype對象上面,意味著可以被所有實例對象繼承。
constructor屬性的作用,是分辨原型對象到底屬于哪個構造函數。
2.6 總結
1.原型和原型鏈是JS實現繼承的一種模型。
2.原型鏈的形成是真正是靠__proto__ 而非prototype。
3.常見問題
訪問對象原型的方法有哪些?
4.解決方法
獲取實例對象obj的原型對象,有三種方法:
1. obj.__proto__
2. obj.constructor.prototype
3. Object.getPrototypeOf(obj)
上面三種方法之中,前兩種都不是很可靠。最新的ES6標準規定,__proto__屬性只有瀏覽器才需要部署,其他環境可以不部署。而obj.constructor.prototype在手動改變原型對象時,可能會失效。
5.編碼實戰
6.擴展思考
1.Object.__proto__ === Function.prototype // true
2.Function.__proto__ === Function.prototype // true
3.Function.prototype.__proto__ === Object.prototype //true
1.Object是函數對象,是通過new Function()創建,所以Object.__proto__指向Function.prototype。
2.Function 也是對象函數,也是通過new Function()創建,所以Function.__proto__指向Function.prototype。
3.Function.prototype是個函數對象,理論上其__proto__應該指向 Function.prototype,就是它自己,自己指向自己,沒有意義。函數對象也是對象,給它設定根指向Object.prototype,Object.prototype.__proto__ === null,保證原型鏈能夠正常結束。
7.參考文獻
參考二:zhangjiahao8961:JavaScript原型及原型鏈詳解
8.更多討論
JavaScript 對象的繼承機制
鳴謝
感謝大家觀看
視頻鏈接
------------------------------------------------------------------------------------------------------------------------
今天的分享就到這里啦,歡迎大家點贊、轉發、留言、拍磚~
下期預告:簡述JS面向對象編程,不見不散~