本文由用途意義,進(jìn)行腦測解析斟湃,從需求角度走一遍原型鏈的發(fā)展熏迹。
用對象模擬類的繼承
js中沒有類(沒有類,沒有類凝赛,重要的事情說3遍)只有對象注暗,怎么才能做到繼承的效果坛缕?
var a={x:1}
var b={};
b.__proto__=a;
接下來進(jìn)行約定,當(dāng)訪問b.x
但不存在時捆昏,就自動去訪問b.__proto__.x
赚楚。
邏輯上就這么一回事。不過需要注意骗卜,這里說的只是訪問宠页。b.x=2
這種是無法對a,也就是b.__proto__
造成影響的寇仓;同時這個為b賦予了x屬性举户,b.x
將覆蓋掉b.__proto__.x
。
通俗點總結(jié)焚刺,就是給對象掛一個父對象敛摘,當(dāng)對象沒有相應(yīng)屬性時,就去它父對象那里找乳愉。
__proto__指向構(gòu)造函數(shù)的prototype
var A=function(){ }
var b = new A();
這個時候又該怎樣用__proto__實現(xiàn)繼承效果兄淫?
首先函數(shù)也是一個對象,除了A();
這樣以函數(shù)調(diào)用蔓姚,還能A.x=1;
這樣把A當(dāng)普通對象使用(下文中函數(shù)捕虽、函數(shù)對象,都是一回事)坡脐。知道這個后實現(xiàn)繼承很簡單泄私,增加一個屬性即可:
A.prototype={constructor: A};//提醒一下怕忘記了,這里相當(dāng)于A增加了屬性prototype
A.prototype.x=1;
b.__proto__ = A.prototype;
js會為每個這樣new出來的對象做這個處理备闲,自己不用寫晌端。
顯然,這里的A.prototype
就類似與一開始例子中的a
恬砂,往A.prototype增加屬性咧纠,那么所有new A()
出來的對象都能訪問到這個新的屬性。
為什么js要默認(rèn)增加constructor: A
這個屬性到prototype中泻骤?這里與new操作符有關(guān)漆羔,是為了解決另一個問題。另外常說的prototype的構(gòu)造函數(shù)狱掂,就是指這個演痒。
總結(jié):
反正就是通過new 函數(shù)()
這樣出來的對象,其__proto__默認(rèn)指向構(gòu)造函數(shù)(這里說的是函數(shù)對象本身趋惨,它跟在new后面也被稱作構(gòu)造函數(shù))的prototype屬性鸟顺。
實際上我覺得一般不以這個方法進(jìn)行有大量屬性的繼承,一是查找有無屬性的效率問題器虾,二是new時構(gòu)造方法把this改為新建對象的指向就足以完成屬性的添加和賦值诊沪,無需操作prototype進(jìn)行繼承养筒。
值得注意的要點
__proto__、prototype是什么一回事相信已經(jīng)了解端姚,剩下的就是經(jīng)常把人繞暈的Object.prototype、Function.prototype這些東西了挤悉。
先提一下渐裸,Object
、Function
都是一個函數(shù)對象装悲,跟上面的A
差不多昏鹃,既能new Object()
也能Object.xxx
這樣用。
Object:
1.所以var b=new Object();
后诀诊,b.__proto__===Object.prototype
這個應(yīng)該沒有什么疑問洞渤。
2.新的標(biāo)準(zhǔn)中可用b=Object.creat(a)
,可當(dāng)作是b=new Object(); b.__proto__=a
属瓣,還是這套操作载迄,問題不大。
3.如果是var b={}
這種直接通過字面量創(chuàng)建對象抡蛙,js會自動進(jìn)行b.__proto__=Object.prototype
护昧,知道后問題也不大。
4.就是默認(rèn)情況下粗截,你不手動搞__proto__惋耙、prototype的指向,最終__proto__都會去指向Object.prototype熊昌。
5.Object.prototype
本質(zhì)上跟前面示例中的prototype沒什么不同绽榛,只是這個prototype會被js自動增加一些屬性
6.Object.prototype.__proto__===null
跟在c++/java中遍歷鏈表一樣,當(dāng)__proto__為null時說明到頭了婿屹。當(dāng)作js自動設(shè)置上去的就行灭美,沒什么其他特殊
7.Object.__proto__===Function.prototype
下面再講。
Function:
1.所有的函數(shù)對象都是Function的實例选泻。
不是說沒有類嗎冲粤,這個實例又是什么意思?
emmm页眯,習(xí)慣說法而已梯捕,具體什么操作沒研究也不懂,或許當(dāng)作js自動這樣做:
var f=function(){}
f.__proto__=Function.prototype;
//或者這樣理解
var f=new Function();
然后把你的代碼放進(jìn)去f
2.Function.__proto__===Function.prototype;
前面提過Object窝撵、Function都是一個函數(shù)對象傀顾,把它們代入第1點例子的f
就行。上面第6點同理碌奉。
按照理解短曾,可能會這樣的疑問:Function.__proto__指向構(gòu)造函數(shù)(再次提醒寒砖,是一個對象)的prototype,所以Function這個對象的構(gòu)造函數(shù)是它自己嫉拐?自己創(chuàng)建自己么哩都?
額。婉徘。漠嵌。我覺得這種操作可能就是為了統(tǒng)一,只要記住“所有函數(shù)對象的__proto__都是Function.prototype”就行盖呼。
3.Function.prototype.__proto__===Object.prototype;
沒什么特別的儒鹿,把Function.prototype
代入上面Object第1點的b
就行,不要特殊看待几晤,硬要說與b
不同的話约炎,只是因為“函數(shù)對象的prototype默認(rèn)會被增加一個constructor屬性”而已,沒什么大問題
總結(jié):
1.我們在js中說的“類型”蟹瘾,可以說只是習(xí)慣用語圾浅,實際上仍舊是沒有所謂的類概念的,只有用對象來“模擬類”热芹。
2.prototype就是指向一個普通對象prototype=new Object()
贱傀,只不過這個對象被添加其他一些屬性后,再被自動放到到函數(shù)對象的屬性中伊脓。
3.__proto__就是 原型/原型對象府寒,不斷的找原型的原型最終到--->Object.prototype--->Object.prototype.__proto__ (null)。原型對象可能是一個普通的對象报腔;也可能是js自動放入到函數(shù)對象的prototype
4.我覺得js這套東西根本目的是批量為對象賦予屬性同時減少代碼冗余株搔,上面解析的Object
、Function
纯蛾、例子中的A
都只是函數(shù)對象纤房,不是像java一樣的類,平時說對象的類型只是方便日常交流翻诉,instanceof也只是很粗暴的遞歸比較對象__proto__ === 函數(shù)對象.prototype
這種炮姨。把類的概念丟掉,保留對象碰煌、屬性這概念舒岸,從這出發(fā)又回頭去實現(xiàn)“類”、“繼承”這東西芦圾,就出來這么套東西蛾派。