根據(jù)自己手繪的簡圖更進一步理解JavaScript的原型鏈機制
原型與隱式原型
概念
- 原型:所有的 函數(shù) 都有一個屬性名叫做
prototype
的屬性但绕;這個屬性的值是一個對象喻喳;這個屬性就是原型。 - 隱式原型:所有的 對象 都有一個叫做
__proto__
的屬性已维;它的屬性值又是一個普通的對象杈笔;這就是隱式原型代乃。
談到隱式原型耻涛,它是以雙下劃線開頭和結尾的烘绽,表示它是私有的,不公開的。 它原本不是 ES 的標準终佛,無奈眾多瀏覽器早早地都實現(xiàn)了這個屬性俊嗽,而且應用得還挺廣泛的。ES 為了向下兼容性只好接納它成為標準的一部分铃彰,是一個典型的現(xiàn)實倒逼標準的例子乌询。
函數(shù)的特殊性
函數(shù)既有prototype
又有__proto__
原型與隱式原型之間的關系
如果對象 f1 是由構造器 F 所創(chuàng)建的,那么如下關系成立:
f1.__proto__===F.prototype
即 對象的隱式原型 指向創(chuàng)建這個對象的構造器的 原型對象豌研。
原型鏈
JavaScript 是基于原型的語言。當我們調用一個對象的屬性時唬党,如果對象沒有該屬性鹃共,JavaScript 解釋器就會從對象的原型對象上去找該屬性,如果原型上也沒有該屬性驶拱,那就去找原型的原型霜浴。這種屬性查找的方式被稱為原型鏈(prototype chain)。
JavaScript中的兩條鏈
- 作用域鏈:作用是確定函數(shù)中變量的值蓝纲。
- 原型鏈:作用是確定對象的屬性的值阴孟。
當然屬性的本質上也是變量,之所以稱為屬性是因為它屬于某一個對象
在JavaScript設計之初是沒有類的概念的(ES6之前)税迷,原型系統(tǒng)確是最初就有的語言設計永丝。原型鏈的設計就是為了能夠讓多個實例對象可以共享一些相同的屬性和方法,模擬繼承的方式箭养。
原型繼承經(jīng)常被視為JavaScript的一個弱點慕嚷,但事實上原型繼承模型比經(jīng)典的繼承模型可能更強大。從某種程度上說毕泌,它是更加純粹的面向對象設計(區(qū)別于其他編程語言的面向類的設計)喝检,畢竟在JavaScript中一切皆是對象。
圖解原型鏈
話不多說上圖先概述
以f1為例撼泛,假設現(xiàn)在要訪問對象 f1 的 a 屬性挠说,即通過 f1.a 或者是 f1[a]來訪問這個屬性。它會按如下步驟去找這個 a 屬性:
第一步:在 f1 對象的自有屬性中找愿题,如果找到 a损俭,則返回 f1.a,如果找不到抠忘,則進入第二步撩炊。
第二步:通過 f1 對象的隱式原型指向構造 f1 的函數(shù) Fun 的原型對象即Fun.prototype
,如果在這里找到了屬性 a 崎脉,則返回 f1.__proto__.a
, 如果找不到骆膝,則繼續(xù)下一步阅签。
第三步: f1.__proto__
即 Fun.prototype
這個對象本身是一個對象,它應該是由內置對象構造器Object構造的路克,那么它的隱式原型指向的就是這個對象構造器的原型即Object.protoype
养交,在這里要繼續(xù)查詢屬性 a 碎连,如果找到了則返回f1.__proto__.__proto__.a
,如果找不到廉嚼,則繼續(xù):
第四步:f1.__proto__.__proto__
即 Object.protoype
這個對象的隱式原型指向的這個對象本身的構造器的原型對象即Object.protoype.__proto__
去找怠噪,發(fā)現(xiàn)為null峭梳,即到達了原型鏈的頂部葱椭,而且還沒有找到屬性 a 捂寿,則返回 undefined孵运。
整個查找 a 屬性的過程治笨,是按一個鏈式結構在找,這個鏈就是原型鏈旷赖。
由于原型鏈的存在,它的查找是自發(fā)的過程稚照,中間的__proto__
可以都省略掉。
代碼驗證
同理可得另外兩個例子的代碼驗證:
要點1:對象是由函數(shù)創(chuàng)造的 - 構造器
- 在JavaScript中,函數(shù) 可以用來創(chuàng)建對象(區(qū)別于其他面向對象的程序設計中辨萍,能夠創(chuàng)建對象的叫類锈玉,ES6之前JS還沒有類的概念)义起,用于創(chuàng)建創(chuàng)建對象的 函數(shù) 就稱為 構造器(constructor)并扇。
- 函數(shù) 如果希望當做構造器來用穷蛹,需要在前面加 new 關鍵字昼汗;不加new就是普通函數(shù)調用顷窒。
- 任何函數(shù)都可以當做構造器使用,前面加 new 即可
- 一般約定打算作為構造器用的函數(shù)鞋吉,首字母大寫
- 獲取創(chuàng)建對象的構造器的方法:
對象.__proto__.constructor
要點2:構造函數(shù)的原型對象中有個屬性指向構造函數(shù)本身
構造函數(shù).prototype.constructor === 構造函數(shù)
要點3:原型鏈終點
根據(jù)定義,null 沒有 prototype谓着,并作為這個原型鏈的最后一個環(huán)節(jié)泼诱。根據(jù)驗證Object.prototype
的隱式原型指向的就是null;所以說JavaScript中幾乎所有的對象都是位于原型鏈頂端的Object的實例赊锚。
以上就是我對JavaScript中原型鏈的理解以及小結如有錯誤望告知!不勝感激??