摘要:我們畫張圖來表示圖中這條紅色的線就是原型鏈。我們把方法放到實(shí)例的原型對(duì)象上面,也就是上面來供所有實(shí)例使用小明小紅用圖表示補(bǔ)充說一下我的經(jīng)歷,一開始理解原型鏈時(shí),一直在在這個(gè)三個(gè)屬性中繞來繞去。
一直以來對(duì)于JavaScript 的原型鏈的概念,始終有些東西有一種模糊感,最近剛好有時(shí)間就塌下心認(rèn)真的把《JavaScript高級(jí)程序設(shè)計(jì)》中相關(guān)內(nèi)容認(rèn)真讀了一遍,也查看了很多網(wǎng)上很多資料,以前很多不明白的地方也漸漸明白了起來。
寫一篇文章記錄一下最近學(xué)習(xí)的感悟。
我們通常創(chuàng)建一個(gè)對(duì)象無非就兩種方式:
1. var obj= new Object();//new 一個(gè)Object的實(shí)例 2. var obj= {};//對(duì)象字面量
使用對(duì)象字面量 和使用new的方式是一樣的。
為了簡便,一般推薦使用使用字面量:var o= {};
當(dāng)我們想要?jiǎng)?chuàng)建自定義的對(duì)象時(shí),需要用到構(gòu)造函數(shù)。
構(gòu)造函數(shù)和普通函數(shù)有兩個(gè)區(qū)別:
1. 便于和普通函數(shù)區(qū)分,函數(shù)名首字母大寫。 2. 使用 `new` 操作符調(diào)用,返回一個(gè)實(shí)例對(duì)象。
除此之外和普通函數(shù)一摸一樣。
我們使用構(gòu)造函數(shù)Person來創(chuàng)建兩個(gè)實(shí)例對(duì)象:
function Person(name){ this.name = name; this.sayName= function (){ alert(this.name) } } var person1 = new Person("小明"); var person2 = new Person("小紅"); console.log(person1);//{name: "小明", sayName: fun} console.log(person2);//{name: "小紅", sayName: fun}
上面的例子不難理解,雖然這兩個(gè)實(shí)例對(duì)象都有sayName方法,而且他們兩個(gè)的作用也是一樣的,但卻是兩個(gè)方法,只是名字和作用一樣。
畫個(gè)圖表示一下:
如果還不明白,我在打個(gè)比喻:
就像A街上有一間麥當(dāng)勞,在B街上也開了一間麥當(dāng)勞,它們都叫麥當(dāng)勞,作用也是一樣的。但是你總不能說他們是一間麥當(dāng)勞吧?
person1.sayName === person2.sayName;//false
如果這樣的話,我們每構(gòu)造出來一個(gè)對(duì)象,都要多帶帶為這個(gè)對(duì)象創(chuàng)建出一個(gè)專屬于它自己使用的sayName,這是很占用內(nèi)存的。
那我們能不能讓所有的實(shí)例對(duì)象都共同使用一個(gè)sayName方法,來節(jié)省內(nèi)存,提升效率呢?這需要我們先理解原型對(duì)象的概念。
原型對(duì)象我們先了解原型對(duì)象的概念。
每個(gè)對(duì)象都有原型對(duì)象(null除外),我們用__proto__表示,每個(gè)函數(shù)都有prototype屬性,指向?qū)嵗脑蛯?duì)象。
對(duì)照這句話,按照我們上面的例子,也就是說Person.prototype指向person1的原型對(duì)象(__proto__),
Person.prototype === person1.__proto__; // true
為了便于理解,來看一張圖。
恩~他們的關(guān)系大概就是這樣。
原型鏈原型鏈簡單用一句話概括就是:
原型鏈就是 對(duì)象的__proto__所連接的鏈狀結(jié)構(gòu)
為了方便我們理解原型鏈,舉一個(gè)簡單的例子:
function F(){ this.a = 1; this.b = 2; } F.prototype.b = 3; F.prototype.c = 4; var o = new F();// {a: 1, b: 2} //原型鏈: //o --> o.__proto__ --> o.__proto__.__proto__ --> null // 其中的 --> 就表示 __proto__ 也就是原型鏈 console.log(o.a); // 1 // o上有a這個(gè)屬性嗎?有的,該屬性的值為1 console.log(o.b); // 2 // o上有b這個(gè)屬性嗎?有的,該屬性的值為2 // 原型上也有一個(gè)"b"屬性,但是它不會(huì)被訪問到.這種情況稱為"屬性遮蔽 " console.log(o.c); // 4 // o上有c這個(gè)屬性嗎?沒有,那看看原型上有沒有 // o.__proto__上有c這個(gè)屬性嗎?有的,該屬性的值為4 console.log(o.d); // undefined // o上有d這個(gè)屬性嗎?沒有,那看看原型上有沒有 // o.__proto__ 上有d這個(gè)屬性嗎?沒有,那看看它的原型上有沒有 // o.__proto__.__proto__ 為 null,停止搜索 // 沒有找到d屬性,返回undefined。
我們畫張圖來表示:
圖中這條紅色的線就是原型鏈。
由此可見,實(shí)例對(duì)象可訪問自己原型對(duì)象上的屬性和方法,額..準(zhǔn)確來說是:
當(dāng)一個(gè)對(duì)象 查找屬性或方法時(shí),自己有,停止查找,返回結(jié)果。
自己沒有,順著__proto__一直向上查找,如找到,停止查找,返回結(jié)果。
如果一直找到了原型鏈的最頂端(null),還沒有找到,返回undefined。
我們先回顧一下那個(gè)sayName的問題:
怎么讓所有的實(shí)例對(duì)象都是用一個(gè)sayName方法呢。
現(xiàn)在我們可以使用原型對(duì)象來解決這個(gè)問題了。
我們把sayName方法放到實(shí)例的原型對(duì)象上面,也就是Person.prototype上面來供所有實(shí)例使用:
function Person(name){ this.name = name; } Person.prototype.sayName=function (){ alert(this.name); } var person1 = new Person("小明"); var person2 = new Person("小紅"); person1.sayName === person2.sayName;//true
用圖表示:
constructor
說一下我的經(jīng)歷,一開始理解原型鏈時(shí),一直在prototype、__proto__、constructor在這個(gè)三個(gè)屬性中繞來繞去。
為了便于理解,我把constructor放在最后了。
constructor字面意思就很容易理解,構(gòu)造函數(shù)的意思。
一句話解釋:
每個(gè)原型對(duì)象都有一個(gè) constructor 屬性指向 關(guān)聯(lián)的構(gòu)造函數(shù)。
還是上面那個(gè)例子:
console.log(Person.prototype.constructor);//Person(){ fun }
需要注意的一點(diǎn)是,實(shí)例對(duì)象上沒有constructor屬性。
但是:
console.log(person1.constructor) ;//Person(){ fun }
得出這個(gè)結(jié)果很簡單:
實(shí)例上查找不到constructor屬性 --> 順著__proto__在原型對(duì)象上找 --> 找到并返回。
Object.prototype
剛才我們說了創(chuàng)建對(duì)象的兩種方式:字面量創(chuàng)建對(duì)象和使用new操作符創(chuàng)建對(duì)象。
這兩種方式創(chuàng)建出來的對(duì)象都會(huì)繼承Object.prototyoe上的方法。
比如,我們使用字面量新創(chuàng)建一個(gè)對(duì)象o:
var o = {value: 1}; o.toString();//"[object Object]" //查找過程: o --> o.__proto__ 找到返回 o.__proto__ === Object.prototype;//true
o這個(gè)的對(duì)象本身并沒有toString這個(gè)方法,但它卻可以使用toString方法。
因?yàn)樗^承了Object.prototyoe上的toString的方法。
null
既然對(duì)象都會(huì)繼承自Object.prototype上面的方法,那它自己的原型又是什么呢。答案是null
Object.prototype.__prototype__ === null;//true
以上僅自己學(xué)習(xí)所得,如有不當(dāng)之處 望指出。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/101194.html
摘要:一些額外的全局函數(shù)命名空間對(duì)象接口和構(gòu)造函數(shù)與沒有典型的關(guān)聯(lián),但卻是有效的。最后有幾點(diǎn)需要說明的是每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象,原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針,而實(shí)例都包含一個(gè)指向原型對(duì)象的內(nèi)部指針。 文章來源:小青年原創(chuàng)發(fā)布時(shí)間:2016-07-03關(guān)鍵詞:JavaScript,原型鏈,jQuery類庫轉(zhuǎn)載需標(biāo)注本文原始地址: http://zhaomenghuan.githu...
摘要:只是構(gòu)造函數(shù)上的一個(gè)屬性,它是一個(gè)指針,指向原型對(duì)象,并不表示就是原型對(duì)象。在上一個(gè)例子中,就是一個(gè)對(duì)象,這個(gè)對(duì)象可以說是原生構(gòu)造函數(shù)的實(shí)例,所以也是一個(gè)對(duì)象,所以它也有屬性,不過它的指向也就是原型鏈的頂端,再往上就沒有了。 上一篇講了①原型對(duì)象是什么;②__proto__、prototype、constructor的關(guān)系;③原型對(duì)象的作用;④原型對(duì)象帶來的一些需要注意的問題; 沒理解...
摘要:也就是說這個(gè)外部函數(shù)的作用域就是閉包本身。無論通過何種手段直接或間接將內(nèi)部函數(shù)傳遞到所在的詞法作用域以外,它都會(huì)持有對(duì)原始定義作用域的引用,無論在何處執(zhí)行這個(gè)函數(shù)都會(huì)使用閉包。 以下是個(gè)人對(duì)這三個(gè)老大難的總結(jié)(最近一直在學(xué)習(xí)原生JS,翻了不少書,不少文檔,雖然還是新手,但我會(huì)繼續(xù)堅(jiān)持走我自己的路) 原型鏈 所有對(duì)象都是基于Object.prototype,Object.prototyp...
摘要:為什么要學(xué)習(xí)設(shè)計(jì)模式做事情之前問個(gè)為什么總是好的。設(shè)計(jì)模式的使用方法關(guān)于使用方式,像我這種初學(xué)者最容易犯的錯(cuò)誤就是生搬硬套,但是模仿本來也是學(xué)習(xí)的一個(gè)過程,最重要的事情是在模仿中要學(xué)會(huì)思考。 為什么要學(xué)習(xí)設(shè)計(jì)模式? 做事情之前問個(gè)為什么總是好的。關(guān)于設(shè)計(jì)模式的好壞,我在知乎上也看過一些討論,有知友對(duì)其提出過一些疑問,里面有一些關(guān)于設(shè)計(jì)模式的觀點(diǎn): 設(shè)計(jì)模式有何不妥,所謂的荼毒體現(xiàn)在哪...
摘要:構(gòu)造函數(shù)所以,就有了畸形的繼承方式原型鏈繼承三原型鏈繼承改變構(gòu)造函數(shù)的原型對(duì)象繼承了屬性以上例子中,暴露出原型鏈繼承的兩個(gè)問題包含引用類型數(shù)據(jù)的原型屬性,會(huì)被所有實(shí)例共享,基本數(shù)據(jù)類型則不會(huì)。 前言 眾所周知,JavaScript 中,沒有 JAVA 等主流語言類的概念,更沒有父子類繼承的概念,而是通過原型對(duì)象和原型鏈的方式實(shí)現(xiàn)繼承。 于是,我們這一篇講一講 JS 中的繼承(委托)。 ...
閱讀 2482·2021-11-19 09:59
閱讀 2008·2019-08-30 15:55
閱讀 939·2019-08-29 13:30
閱讀 1346·2019-08-26 10:18
閱讀 3092·2019-08-23 18:36
閱讀 2394·2019-08-23 18:25
閱讀 1168·2019-08-23 18:07
閱讀 443·2019-08-23 17:15