摘要:在上面的各種原型的變換中,其實(shí)難點(diǎn)就在于構(gòu)造函數(shù)也是對(duì)象原型對(duì)象等所有對(duì)象都由構(gòu)造這四個(gè)點(diǎn)。
這篇文章主要是學(xué)習(xí)一下JavaScript中的難點(diǎn)------原型和原型鏈自定義一個(gè)對(duì)象
我們學(xué)習(xí)一門編程語(yǔ)言,必然要使用它完成一些特定的功能,而面向?qū)ο蟮恼Z(yǔ)言因?yàn)榉先祟惖恼J(rèn)知規(guī)律,在這方面做得很好,今天我以JS為例,探索一下JS不同于其他面向?qū)ο蟮恼Z(yǔ)言的地方-------原型和原型鏈
首先,假設(shè)你在做一個(gè)項(xiàng)目,要造一個(gè)新的對(duì)象,標(biāo)準(zhǔn)庫(kù)里面沒(méi)有。那你只能用構(gòu)造函數(shù)去構(gòu)造一個(gè)
function Person(){ //構(gòu)造函數(shù) }
以上Person就是一個(gè)構(gòu)造函數(shù),可以用來(lái)生成小明 小紅 等等人類的實(shí)例。
var person = new Person() //構(gòu)造出一個(gè)對(duì)象 person.name = "xiaoming" console.log(person.name) // "xiaoming"
那原型在哪呢,認(rèn)識(shí)原型先認(rèn)識(shí)一下prototype屬性
prototype先看一段代碼
Person.prototype.name = "god" var person2 = new Person() console.log(person2.name) //person2的名字是啥呢???
從上面三行代碼,猜一猜person2的名字是啥,沒(méi)錯(cuò),就是god
person2沒(méi)有自己規(guī)定名字,但是Person構(gòu)造函數(shù)的prototype上綁定了name,所以由Person構(gòu)造函數(shù)構(gòu)造的實(shí)例對(duì)象都默認(rèn)有一個(gè)god的名字。
而且這個(gè)prototype屬性只存在構(gòu)造函數(shù)上,也就是說(shuō)prototype是構(gòu)造函數(shù)的屬性!!!
那這個(gè)prototype指向了哪里,那個(gè)地方就是--------調(diào)用構(gòu)造函數(shù)而生成的對(duì)象實(shí)例的原型,存的是這個(gè)原型的地址。
以上就是構(gòu)造函數(shù)和原型之間的關(guān)系,構(gòu)造函數(shù)內(nèi)部的prototype屬性指向了實(shí)例對(duì)象原型的地址。
原型里面存的是所有實(shí)例化對(duì)象的共有屬性,比如這個(gè)例子的name。
上面紅框是Person實(shí)例的原型,如果不直觀的話,下面直接看Array實(shí)例的原型
紅框的都是大家熟悉的數(shù)組的方法吧,他們都放在數(shù)組的共有屬性里面。
上面的兩幅原型圖里面,我們竟然發(fā)現(xiàn)有共同點(diǎn),都有一個(gè)熟悉 constructor 屬性,待會(huì)研究一下這個(gè)屬性。
現(xiàn)在,我們已經(jīng)知道了構(gòu)造函數(shù)和原型的關(guān)系了,那person person2這些實(shí)例對(duì)象和原型有啥關(guān)系呢
__proto__屬性每一個(gè)構(gòu)造的實(shí)例對(duì)象,內(nèi)部有一個(gè)__proto__屬性,它指向了實(shí)例原型,存的是原型的地址。
person.__proto__ === Person.prototype true
__proto__是對(duì)象的屬性,而且是瀏覽器強(qiáng)逼著ECMAScript加上的這個(gè)規(guī)范。
以上是構(gòu)造函數(shù)、實(shí)例、實(shí)例原型之間的關(guān)系,不過(guò)方向是單向的,哪能不能讓它循環(huán)起來(lái)呢,原型可不可以指向構(gòu)造函數(shù)或者實(shí)例呢?
constructor還記得上面我們發(fā)現(xiàn)的那個(gè) 不同的原型 都有的一個(gè)共同的屬性 constructor嘛
構(gòu)造函數(shù)、實(shí)例、實(shí)例原型之間的關(guān)系的方向可以循環(huán)的關(guān)鍵就在這里了。我們一直叫構(gòu)造函數(shù),構(gòu)造函數(shù)的,為什么這么叫呢,對(duì),就是這個(gè)原型里面的constructor屬性。
不過(guò)原型是無(wú)法指向?qū)嵗模豢梢酝ㄟ^(guò)constructor屬性指向 構(gòu)造函數(shù)
Person === Person.prototype.constructor true
上面就是經(jīng)典的鐵三角了。
由以上知識(shí)得出一個(gè)小公式對(duì)象.__proto__ === 構(gòu)造函數(shù).prototype
而Person這個(gè)構(gòu)造函數(shù)也是對(duì)象,那么
Person.__proto__ === ???
上面的問(wèn)號(hào)填啥呢,我們按公式填空,應(yīng)該是構(gòu)造函數(shù).prototype,Person構(gòu)造函數(shù)的構(gòu)造函數(shù)是誰(shuí)呢?沒(méi)錯(cuò),就是Function。
Person.__proto__ === Function.prototype true
在控制臺(tái)驗(yàn)證確實(shí)如此。
所以有些以前的疑惑也解開(kāi)了
Array.__proto__ === Function.prototype true String.__proto__ === Function.prototype true
那問(wèn)題又來(lái)了,構(gòu)造函數(shù).prototype也是對(duì)象啊,它指向誰(shuí)
既然是對(duì)象,那么里面就有__proto__屬性
Person.prototype.__proto__ === ???
問(wèn)號(hào)填什么呢,原型是由誰(shuí)構(gòu)造的呢,我們想到了所有對(duì)象的根----------Object
原型的原型在控制臺(tái)驗(yàn)證如下
Person.prototype.__proto__ === Object.prototype true Array.prototype.__proto__ === Object.prototype true String.prototype.__proto__ === Object.prototype true
既然引出了Object,我們來(lái)看一下所有對(duì)象的祖宗的原型吧
Object.prototype.__proto__ === null true特殊的Function
前面我們看到了Function構(gòu)造方法構(gòu)造除了所有的函數(shù),包括普通的構(gòu)造函數(shù)。
那么他自身也是一個(gè)函數(shù),所以也是由Function構(gòu)造函數(shù)構(gòu)造的。所以由總結(jié)的公式可以知道
Function.__proto__ === Function.prototype
而且,下面這個(gè)很重要,易錯(cuò)
Function.prototype === Object.__proto__ //哈哈,這個(gè)老別扭了吧,還給你倒過(guò)來(lái)寫,很容易錯(cuò)的
解釋:Object也是構(gòu)造函數(shù)啊,屬于對(duì)象。Object構(gòu)造函數(shù)也是由Function把它構(gòu)造出來(lái)的,所以是結(jié)果是true
完整的總結(jié)instanceof運(yùn)算符的實(shí)質(zhì)當(dāng)你new一個(gè)構(gòu)造函數(shù)的時(shí)候,創(chuàng)建一個(gè)函數(shù)實(shí)例,那么 『 函數(shù)實(shí)例.__proto__ === 該構(gòu)造函數(shù).prototype 』
所有的函數(shù)都是由Function構(gòu)造出來(lái)的,那么 『被構(gòu)造出來(lái)的其他函數(shù).__proto__ === Function.prototype 』
所有的構(gòu)造函數(shù)的原型對(duì)象都是由Object構(gòu)造出來(lái)的,那么 『所有的構(gòu)造函數(shù).prototype.__proto__ === Object.prototype 』
首先這有幾個(gè)題
Object instanceof Function Function instanceof Object Function instanceof Function Object instanceof Object
能不假思索的說(shuō)出來(lái)嗎,大聲告訴我,答案是什么。
沒(méi)錯(cuò),全是true
雖然 instanceof運(yùn)算符算是我們的老朋友了,不過(guò)背后是咋判斷的呢
規(guī)范是這么寫的
object instanceof constructor參數(shù)object
要檢測(cè)的對(duì)象.
constructor
某個(gè)構(gòu)造函數(shù)
instanceof 運(yùn)算符用來(lái)檢測(cè) constructor.prototype 是否存在于參數(shù) object 的原型鏈上
對(duì)于 Object instanceof Function ,Object.__proto__ === Function.prototype 為true,解決
對(duì)于Function instanceof Object , Function.__proto__.__proto__ === Function.prototype.__proto__ === Object.prototype為true,解決。
對(duì)于 Function instanceof Function ,Function.__proto__ === Function.prototype 為true,解決
對(duì)于Object instanceof Object , Object.__proto__.__proto__ === Function.prototype.__proto__ === Object.prototype 為true,解決
只要上面的推導(dǎo),任一環(huán)節(jié)你寫錯(cuò)或者壓根寫不出來(lái)(在今天之前我也是瞎搞,運(yùn)氣好了蒙對(duì)了),說(shuō)明你就不是真懂原型鏈,面試問(wèn)到稍微變形的題還是易錯(cuò)。
在上面的各種原型的變換中,其實(shí)難點(diǎn)就在于Function Object 構(gòu)造函數(shù)也是對(duì)象 原型對(duì)象等所有對(duì)象都由Object構(gòu)造
這四個(gè)點(diǎn)。
而且看待問(wèn)題的角度不同,對(duì)事實(shí)的認(rèn)知影響很大。比如 Object Function 你把它們看成構(gòu)造函數(shù)或者對(duì)象,結(jié)果不同的。不同的場(chǎng)合,換不同的角度去認(rèn)識(shí)它們,事物具有兩面性。大概就是背了多年的同一性,巴拉巴拉一堆的哲學(xué)原理吧。
各種原型的分析過(guò)程,讓我回憶起了,被數(shù)學(xué)支配的恐懼。邏輯必須合理、一步是一步、抽絲剝繭看本質(zhì),大概是這么多年應(yīng)試教育留在腦子里面的深深烙印吧。
JS越來(lái)越有意思了,感覺(jué)應(yīng)該快入門了。
原型鏈咦,在哪呢。
原型鏈就在上面啊。每個(gè)對(duì)象,沿著__prto__屬性有一條鏈子,找呀找呀,一直找到Object.prototype為止
感謝冴羽大神和若愚大神的文章。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/92521.html
摘要:在上面的各種原型的變換中,其實(shí)難點(diǎn)就在于構(gòu)造函數(shù)也是對(duì)象原型對(duì)象等所有對(duì)象都由構(gòu)造這四個(gè)點(diǎn)。 這篇文章主要是學(xué)習(xí)一下JavaScript中的難點(diǎn)------原型和原型鏈 自定義一個(gè)對(duì)象 我們學(xué)習(xí)一門編程語(yǔ)言,必然要使用它完成一些特定的功能,而面向?qū)ο蟮恼Z(yǔ)言因?yàn)榉先祟惖恼J(rèn)知規(guī)律,在這方面做得很好,今天我以JS為例,探索一下JS不同于其他面向?qū)ο蟮恼Z(yǔ)言的地方-------原型和原型鏈 首...
摘要:為了防止之后自己又開(kāi)始模糊,所以自己來(lái)總結(jié)一下中關(guān)于作用域鏈和原型鏈的知識(shí),并將二者相比較看待進(jìn)一步加深理解。因此我們發(fā)現(xiàn)當(dāng)多個(gè)作用域相互嵌套的時(shí)候,就形成了作用域鏈。原型鏈原型說(shuō)完了作用域鏈,我們來(lái)講講原型鏈。 畢業(yè)也整整一年了,看著很多學(xué)弟都畢業(yè)了,忽然心中頗有感慨,時(shí)間一去不復(fù)還呀。記得從去年這個(gè)時(shí)候接觸到JavaScript,從一開(kāi)始就很喜歡這門語(yǔ)言,當(dāng)時(shí)迷迷糊糊看完了《J...
摘要:原型鏈繼承和參考理解的原型鏈和繼承實(shí)現(xiàn)了什么操作的過(guò)程發(fā)生了什么原型鏈和屬性原型鏈?zhǔn)鞘裁瓷厦娴氖鞘裁淳褪窃玩湥玩準(zhǔn)莾?nèi)部,指向它父類的。通過(guò)這一句說(shuō)明的原型鏈就是指向函數(shù)的屬性。這可以為后面提到的繼承做準(zhǔn)備。 原型鏈、繼承 和 instanceof 參考:MDN:instanceofMDN:Inheritance and the prototype chain理解JavaScrip...
摘要:在使用原型鏈實(shí)現(xiàn)繼承時(shí)有一些需要我們注意的地方注意繼承后的變化。在了解原型鏈時(shí),不要忽略掉在末端還有默認(rèn)的對(duì)象,這也是我們能在所有對(duì)象中使用等對(duì)象內(nèi)置方法的原因。 在上一篇post中,介紹了原型的概念,了解到在javascript中構(gòu)造函數(shù)、原型對(duì)象、實(shí)例三個(gè)好基友之間的關(guān)系:每一個(gè)構(gòu)造函數(shù)都有一個(gè)守護(hù)神——原型對(duì)象,原型對(duì)象心里面也存著一個(gè)構(gòu)造函數(shù)的位置,兩情相悅,而實(shí)例呢卻又...
閱讀 1440·2021-11-22 15:24
閱讀 2534·2021-10-11 11:06
閱讀 2339·2021-10-09 09:45
閱讀 2539·2021-09-09 09:33
閱讀 646·2019-08-30 15:53
閱讀 1451·2019-08-30 12:48
閱讀 692·2019-08-29 13:47
閱讀 513·2019-08-26 18:27