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