認(rèn)識原型鏈
要理解js的繼承原來要先理解原型鏈示损,要理解原型鏈要先清楚下面兩個結(jié)論:
- 任何一個構(gòu)造函數(shù)(其實是任何一個函數(shù))都有一個
prototype
屬性渗磅,這個屬性指向指向這個函數(shù)的原型對象。為了直觀的理解原型對象检访,我們把構(gòu)成對象的函數(shù)Object()
的prototype
屬性打印出來看看:
可以看到Object()
的prototype
就是一個對象始鱼,這個對象的屬性基本都是所有Object類型共有的方法如hasOwnProperty()
。特別的烛谊,用紅色矩形框標(biāo)記的constructor
屬性指向了Object()
本身风响。到這里,我們給出第一個結(jié)論:任何一個構(gòu)造函數(shù)(其實是任何一個函數(shù))F
都有一個原型對象prototype
丹禀,prototype
存儲了F
的所有實例共有的屬性和方法(一般是方法)状勤;prototype
還有一個屬性constructor
直接指向這個構(gòu)造函數(shù)本身(如下圖示)
- 前面說到,構(gòu)造函數(shù)的原型對象存儲了這個構(gòu)造函數(shù)的所有實例共有的屬性和方法双泪,那么實例是通過什么路徑找到這些方法的呢?為了回答這個問題持搜,我們打印一個實例出來看看:
上面我們創(chuàng)建一個Object()
的實例instance
并給這個實例增加一個屬性"name"
。但是打印出來會發(fā)現(xiàn)除了"name"
屬性還多了一個"_proto_"
屬性焙矛,而且這個"_proto_"
居然指向的就是Object()
的prototype
:巍(如下圖示)
可以想象,運行var instance = new Object();
的過程中肯定有instance._proto_ =Object.prototype;
這個步驟村斟。這里贫导,給出第二個結(jié)論:構(gòu)造函數(shù)F
的任何一個實例instance
都一個屬性"_proto_"
直接指向F
的prototype
。當(dāng)instance
調(diào)用一個屬性或者方法時蟆盹,會先去查找instance
的自有屬性和方法孩灯,如果找到就直接調(diào)用,否則沿著"_proto_"
到F
的prototype
中查找逾滥。這樣峰档,F
的所有實例就共有了F
的prototype
中的屬性和方法,這些實例也可以定義同名的屬性和方法覆蓋掉這些共有方法寨昙。
通過前面兩個結(jié)論讥巡,我們知道了構(gòu)造函數(shù)F
的實例instance
可以沿著"_proto_"
到找到F.prototype
從而調(diào)用prototype中的方法。如果F.prototype
是另外一個構(gòu)造函數(shù)F1
的實例(也就是F.prototype=new F1()
)會出現(xiàn)什么情況呢?通過前面的基礎(chǔ)舔哪,可以簡單的推出F.prototype._proto==instance._proto_._proto_==F1.prototype
欢顷,我們看到F
的實例instance
居然通過instance._proto_._proto_
這樣的鏈?zhǔn)铰窂秸业搅?code>F1的prototype
。那這樣沿著不只一個_proto_
找到的prototype
中的方法能被instance
調(diào)用嗎?答案是肯定的捉蚤!F
的實例獲得了F1
的方法和屬性吱涉,這不就是F
繼承了F1
刹泄!延長一下我們的鏈?zhǔn)铰窂剑?/p>
Fn-1.prototype._proto=new Fn();
...
F1.prototype=new F2();
F.prototype=new F1();
instance = new f();
//那么下面顯然就成立
instance._proto_._proto_....._proto_ == Fn.prototype;
F
一代一代的繼承了F1
到Fn
,F
的實例instance
通過._proto_._proto_....._proto_
這個長鏈繼承了所有構(gòu)造函數(shù)的方法怎爵。這個長鏈就是原型鏈特石!可以說javascript的繼承主要就是依靠原型鏈實現(xiàn)的。
instanceof的原理
js中使用instance instanceof F
檢測對象instance
是不是F
的實例鳖链,檢測的原理就是檢查F.prototype
是否被instance._proto_._proto_....._proto_
鏈中其中一個_proto_
指向姆蘸。
繼承的方法
未完待續(xù)...