首先列出經(jīng)常會聽到的屬性魏滚,之后來說明它們之間的關(guān)系镀首,再進一步解釋如何通過這些屬性構(gòu)建JS的層層繼承。
屬性
proto所有的對象都擁有這個屬性鼠次,這個屬性是繼承的關(guān)鍵更哄。
prototype是函數(shù)獨有的一個屬性,在使用new來構(gòu)建新對象時腥寇,它與新對象的proto屬性有關(guān)成翩。
__proto屬性與prototype屬性都是對象。
這些屬性本身沒有什么特別赦役,但它們之間的關(guān)系卻比較復雜麻敌,下面加上代碼的印證,說清楚他們之間的關(guān)系掂摔。
基礎實現(xiàn)
這里新建一個函數(shù)术羔,函數(shù)也是對象,它有自己的屬性乙漓,我們?yōu)樗膒rototype(原型鏈)屬性添加一個方法introduce,之后通過new方法新建一個子類级历,輸出子類car的name屬性,調(diào)用子類的方法
function Car (name) {
this.name = name;
}
Car.prototype.introduce = function () {
console.log('Hello, my name is: ' + this.name);
}
var car = new Car('Alice');
console.log(car.name);
car.introduce();
繼承的實現(xiàn)
我們學習面向?qū)ο蟮木幊陶Z言叭披,很多時候是為了提高效率和正確性寥殖,而繼承是實現(xiàn)這兩點的關(guān)鍵,既然需要實現(xiàn)繼承涩蜘,那么來JS中是如何實現(xiàn)的嚼贡。
JS創(chuàng)造了prototype屬性在通過函數(shù)構(gòu)造子類時生成proto屬性,通過proto_屬性來連接子類和父類同诫。
于是粤策,我們先從prototype屬性說起,先明確一點剩辟,這個屬性是函數(shù)特有的掐场,這個屬性的作用是為了在使用new來構(gòu)造新對象實例時往扔,可以讓對象實例共享一些函數(shù)。
對于上面的代碼熊户,在使用Car這個構(gòu)造函數(shù)構(gòu)建的對象實例后萍膛,所有的新構(gòu)建的對象實例都會擁有方法introduce。
理解了這里嚷堡,我們來整體看一次蝗罗。
先定義一個構(gòu)造函數(shù)Car,之后為其原型添加方法蝌戒,接著使用new標識符通過構(gòu)造函數(shù)來新建一個對象串塑。等等,這里需要聽一下北苟,為什么一個new可以有這么大的作用桩匪,這里面發(fā)生了什么?
new
那我們先說說new友鼻,它的確執(zhí)行了好幾個步驟傻昙,才產(chǎn)生了一個新對象。
- 首先新建一個空對象car彩扔,每個對象在創(chuàng)建之后妆档,就會擁有一個proto隱藏屬性,這個屬性會原本指向Object屬性的原型對象虫碉,可以通過下面的代碼一窺究竟
var a = {}
a.__proto__
Object {}
__defineGetter__:__defineGetter__()
constructor:Object()
...
a.__proto__ === Object.prototype
// true
- 改變proto屬性的指向贾惦,將它指向Car函數(shù)的prototype屬性
- 讓Car函數(shù)內(nèi)部的this指向新建的對象car
- 執(zhí)行構(gòu)造函數(shù),構(gòu)造函數(shù)也是函數(shù)敦捧,但這個構(gòu)造函數(shù)并沒有返回任何值须板,但在它執(zhí)行的過程中,由于this是指向新對象car的绞惦,所以它會為car的name屬性賦值逼纸。執(zhí)行完畢后洋措,car對象會擁有name屬性济蝉。
原型鏈上的方法
由于現(xiàn)在car.proto引用了Car.prototype引用的對象,那么他們會共享屬性菠发。