摘要:說白了,原型就是構(gòu)造函數(shù)用來構(gòu)造新實(shí)例的模板對象。什么是原型鏈先回答什么是原型。例如這個(gè)原型的原型就是這個(gè)構(gòu)造函數(shù)的,既這個(gè)原型對象。這些原型對象通過像鏈子一樣連起來,就叫做原型鏈。
原型鏈初步學(xué)習(xí)
這篇博客只是我初步理解原型鏈的一個(gè)個(gè)人學(xué)習(xí)筆記,寫的比較粗略,且有的地方可能理解錯(cuò)誤.
更多更專業(yè)的關(guān)于原型鏈的解釋請看JavaScript深入之從原型到原型鏈和阮一峰的博客:Javascript繼承機(jī)制的設(shè)計(jì)思想
JS標(biāo)準(zhǔn)庫里幾個(gè)構(gòu)造函數(shù)之間的關(guān)系
每個(gè)對象都有toString()和valueOf()函數(shù),如果每個(gè)對象里都存這樣的相同的函數(shù),那會浪費(fèi)內(nèi)存.
問題解決方法:原型鏈
把toString()和valueOf()等函數(shù)多帶帶存放在一個(gè)對象里,原來對象里的toString()和valueOf()只存地址,指向這個(gè)地址
當(dāng)聲明對象是,出來自己定義的屬性,還有一個(gè)隱藏的屬性
__proto__ 里面存的是toString()和valueOf()等的地址
他的值就是公用屬性的值
共有的屬性和方法
在執(zhí)行o1.toString()是發(fā)生的事:
首先看o1
是不是真正的對象,如果不是,就包裝成臨時(shí)對象,用完再回收垃圾,然后進(jìn)入對象,看他有沒有toString方法,如果有特有的toString(),就用,如果沒有,就進(jìn)入__proto__屬性去找toString()方法.
說明所有的toString()都是同一個(gè)地址
如果這個(gè)對象不是普通對象擁有特有的方法,會一層一層去找
代碼:
第一層的toString()是Number()特有的,可以轉(zhuǎn)換成16進(jìn)制
toString(16),第二層里面的的toString()是所有對象都有的公共屬性.比如找valueOf()如果在第一層里 __proto__ 找不到,就去第二層找.
數(shù)字對象普通對象
結(jié)構(gòu):
原型鏈
所有的共有屬性,,如果沒有東西引用他,就會被垃圾回收,那么誰在引用他呢?
答案是 prototype ,prototype的意思是 原型.
所有函數(shù)都有protoype屬性,包括構(gòu)造函數(shù).即String(),Number(),Boolean(),Object()有protoype
在最開始JS初始化的時(shí)候,函數(shù)的protoype屬性會加載到內(nèi)存當(dāng)中
原型===共有屬性
Object.prototype意思還是Object的共有屬性
Object是構(gòu)造函數(shù)(JS里函數(shù)也是一種對象,也可以有方法,可以 有屬性)
函數(shù)名字加()就是執(zhí)行.
Number的共有屬性
共有屬性的共有屬性
其他String,Boolean的原型也是一樣
new做的事情,一創(chuàng)造一個(gè)哈希,二綁定原型(共有屬性),即把__proto__指向該有的共有屬性,也就是原型
__proto__與prototype的關(guān)系[__proto__指向prototype],
在無代碼情況下
window里面有Number屬性(函數(shù)也是對象,也可以有屬性)
實(shí)際上為
Number:function Number(){}這個(gè)
無代碼的時(shí)候,即為下面這樣,瀏覽器已經(jīng)將其初始化好了.
可以看到prototype是用來指向這些共有屬性的,不然這些共有屬性就被垃圾回收了,所以要用一個(gè)線來牽引著.
如圖
寫了代碼之后
所以:
prototype是瀏覽器開始就準(zhǔn)備好了的,用來防止共有屬性被垃圾回收的,
__proto__是在開始寫代碼的時(shí)候用來引用共有函數(shù)的.
String.prototype是String的公用屬性的引用,是JS在初始化的時(shí)候就已經(jīng)存在的,用他是因?yàn)槿绻挥盟?那么公用屬性就跑了,被垃圾回收了
"s".__proto__是String的公用屬性的引用,是在聲明新對象的時(shí)候存在的,有他是因?yàn)槲乙盟?用公用屬性
共同點(diǎn)就是都是公共屬性的引用.
var o1 = {}; o1.__proto__ === Object.prototype//true
Number.prototype.__proto__===Object.prototype//true
var s1 = new String("s1"); s1.__proto__ === String.prototype//true
String.prototype.__proto__ ===Object.prototype//true function DOG(name){ this.name = name; } DOG.prototype.__proto__ === Object.prototype//true對象與構(gòu)造函數(shù)
形式
只有函數(shù)才能有prototype
兩個(gè)屬性對比:
共同點(diǎn):存的地址相同,都指向同一個(gè)對象
不同點(diǎn):一個(gè)是對象的屬性,一個(gè)是函數(shù)的屬性
面試題:
1
"1".__proto__
"1"會創(chuàng)建一個(gè)臨時(shí)String對象,然后指向String.prototype
2
函數(shù).prototype 是一個(gè)對象,那么
var obj = 函數(shù).prototype; obj.__proto__ === Object.prototype;//true 函數(shù).prototype.__proto__ === Object.prototype;//true
成立(可以看上圖無代碼的時(shí)候)
Number.prototype.__proto__ === Object.prototype //true String.prototype.__proto__ === Object.prototype //true Boolean.prototype.__proto__ === Object.prototype //true
成立
原型鏈面試:怎么回答
JS 原型是什么?舉例
var a = [1,2,3]
只有0、1、2、length 4 個(gè)key
為什么可以 a.push(4) ,push 是哪來的?
a.__proto__ === Array.prototype(a是實(shí)例數(shù)組對象,Array是構(gòu)造函數(shù))
push函數(shù) 就是沿著 a.__proto__ 找到的,也就是 Array.prototype.push
Array.prototype 還有很多方法,如 join、pop、slice、splice、concat
Array.prototype 就是 a 的原型(proto)
聚完例子后用new對象舉例,說給面試官聽:
比若說
我們新創(chuàng)建一個(gè)構(gòu)造函數(shù)
function Person() {}
然后根據(jù)構(gòu)造函數(shù)構(gòu)造一個(gè)新對象
var person1 = new Person();
每個(gè)函數(shù)都有一個(gè) prototype 屬性,這個(gè)構(gòu)造函數(shù)的 prototype 屬性指向了一個(gè)對象,這個(gè)對象正是調(diào)用該構(gòu)造函數(shù)而創(chuàng)建的實(shí)例的原型。
當(dāng)我們給Person的prototype的name屬性賦值為"Kevin"
Person.prototype.name = "Kevin"; var person1 = new Person(); var person2 = new Person(); console.log(person1.name) // Kevin console.log(person2.name) // Kevin
每一個(gè)新的實(shí)例對象對象都會從原型"繼承"屬性,實(shí)例對象擁有該原型的所有屬性。
說白了,原型就是 構(gòu)造函數(shù) 用來 構(gòu)造 新實(shí)例 的 模板對象。
這就是原型。
開始解釋原型鏈
那么我們該怎么表示實(shí)例與實(shí)例原型,也就是 person1 和 Person.prototype 之間的關(guān)系呢,這時(shí)候我們就要講到第二個(gè)屬性__proto__。
先回答什么是原型。在上面,然后繼續(xù)從__proto__開始往下說。
說:
JavaScript對象除了 null 都具有的一個(gè)屬性,叫__proto__,這個(gè)屬性會指向該對象的原型對象。
當(dāng)讀取實(shí)例的屬性時(shí),如果找不到,就會通過__proto__查找原型中的屬性,如果還查不到,就去找原型的原型。
例如Person.prototype這個(gè)原型的原型就是Object這個(gè)構(gòu)造函數(shù)的prototype,既Object.prototype這個(gè)原型對象。然后,Person.prototype.__proto__就指向Object.prototype這個(gè)原型。然后Object.prototype原型是null。
這些原型對象通過__proto__像鏈子一樣連起來,就叫做原型鏈。
然后給面試官畫:
鏈子上都畫上__proto__
person1----->Person.prototype----->Object.prototype----->null
Array.prototype----->Object.prototype----->null
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/94834.html
摘要:原文鏈接關(guān)于的原型和原型鏈,看我就夠了一參考鏈接闖關(guān)記之原型及原型鏈之原型與原型鏈一篇文章帶你理解原型和原型鏈徹底理解原型鏈一的默認(rèn)指向圖解和的三角關(guān)系原型和原型鏈三張圖搞懂的原型對象與原型鏈 溫故 創(chuàng)建對象的三種方式 通過對象直接量 通過new創(chuàng)建對象 通過Object.create() js中對象分為兩種 函數(shù)對象 普通對象 仔細(xì)觀察如下代碼 function Foo(na...
摘要:既然構(gòu)造函數(shù)有屬于自己的原型對象,那么我們應(yīng)該能讓另一個(gè)構(gòu)造函數(shù)來繼承他的原型對象咯我們在構(gòu)造函數(shù)內(nèi)部執(zhí)行了函數(shù)并改變了函數(shù)內(nèi)部的指向其實(shí)這個(gè)指向的是實(shí)例化之后的對象。 我們在討(mian)論(shi)JavaScript這門語言時(shí),總是繞不過的一個(gè)話題就是繼承與原型鏈。那么繼承與原型鏈到底是什么呢? 我很喜歡的一個(gè)聊天模式是:我不能說XX是什么,我只能說XX像什么。也就是說我不直接跟...
摘要:繼承可以使得子類具有父類別的各種屬性和方法。繼承是類與類之間的關(guān)系。繼承的實(shí)質(zhì)就是兩次的原型搜索,像是實(shí)例屬性而不是繼承,才是繼承。更多用法見繼承。 前言 面試中最常會問到的問題:什么是繼承?如何分別用 ES5 和 ES6 實(shí)現(xiàn)?想要學(xué)習(xí)繼承,必須先學(xué)好原型與原型鏈,如果此部分還不清楚,請先學(xué)習(xí)此部分再來閱讀本文,可參考我的文章JS之原型與原型鏈或?yàn)g覽其他相關(guān)的學(xué)習(xí)網(wǎng)站。 定義 繼承...
摘要:對應(yīng)的關(guān)系圖如下講解了構(gòu)造函數(shù)和原型對象之間的關(guān)系,那么實(shí)例對象和原型對象之間的關(guān)系又是怎么樣的呢下面講解。原型對象的指向的是構(gòu)造函數(shù)和本身沒有屬性,但是其原型對象有該屬性,因此也能獲取到構(gòu)造函數(shù)。 JavaScript進(jìn)階 - 1. 原型和原型鏈的概念 我們好多經(jīng)常會被問道JavaScript原型和原型鏈的概念,還有關(guān)于繼承,new操作符相關(guān)的概念。本文就專門整理了原型和原型鏈的概念...
摘要:的過程新生成了一個(gè)對象鏈接到原型綁定返回新對象在調(diào)用的過程中會發(fā)生以上四件事情,我們也可以試著來自己實(shí)現(xiàn)一個(gè)創(chuàng)建一個(gè)空的對象獲得構(gòu)造函數(shù)鏈接到原型綁定,執(zhí)行構(gòu)造函數(shù)確保出來的是個(gè)對象對于實(shí)例對象來說,都是通過產(chǎn)生的,無論是還是。 showImg(https://segmentfault.com/img/bVbhZun?w=488&h=590); prototype 首先來介紹下 pro...
閱讀 2536·2023-04-25 14:54
閱讀 609·2021-11-24 09:39
閱讀 1819·2021-10-26 09:51
閱讀 3867·2021-08-21 14:10
閱讀 3494·2021-08-19 11:13
閱讀 2700·2019-08-30 14:23
閱讀 1817·2019-08-29 16:28
閱讀 3364·2019-08-23 13:45