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