摘要:而作為構(gòu)造函數(shù),需要有個(gè)屬性用來作為以該構(gòu)造函數(shù)創(chuàng)造的實(shí)例的繼承。
歡迎來我的博客閱讀:「JavaScript 原型中的哲學(xué)思想」
記得當(dāng)年初試前端的時(shí)候,學(xué)習(xí)JavaScript過程中,原型問題一直讓我疑惑許久,那時(shí)候捧著那本著名的紅皮書,看到有關(guān)原型的講解時(shí),總是心存疑慮。
當(dāng)在JavaScript世界中走過不少旅程之后,再次萌發(fā)起研究這部分知識的欲望,翻閱了不少書籍和資料,才搞懂__proto__和prototype的概念。
故以作此筆記,日后忘了可以回來看看。如果你看的過程中覺得理解有些困難,把例子在代碼中跑一跑,親手試一試也許能解決不少疑惑。
一切皆為對象殊不知,JavaScript的世界中的對象,追根溯源來自于一個(gè) null
「一切皆為對象」,這句著實(shí)是一手好營銷,易記,易上口,印象深刻。
萬物初生時(shí),一個(gè)null對象,憑空而生,接著Object、Function學(xué)著null的模樣塑造了自己,并且它們彼此之間喜結(jié)連理,提供了prototype和constructor,一個(gè)給子孫提供了基因,一個(gè)則制造萬千子子孫孫。
在JavaScript中,null也是作為一個(gè)對象存在,基于它繼承的子子孫孫,當(dāng)屬對象。乍一看,null像是上帝,而Object和Function猶如JavaScript世界中的亞當(dāng)與夏娃。
原型指針 __proto__在JavaScript中,每個(gè)對象都擁有一個(gè)原型對象,而指向該原型對象的內(nèi)部指針則是__proto__,通過它可以從中繼承原型對象的屬性,原型是JavaScript中的基因鏈接,有了這個(gè),才能知道這個(gè)對象的祖祖輩輩。從對象中的__proto__可以訪問到他所繼承的原型對象。
var a = new Array(); a.__proto__ === Array.prototype // true
上面代碼中,創(chuàng)建了一個(gè)Array的實(shí)例a,該實(shí)例的原型指向了Array.prototype。
Array.prototype本身也是一個(gè)對象,也有繼承的原型:
a.__proto__.__proto__ === Object.prototype // true // 等同于 Array.prototype.__proto__ === Object.prototype
這就說了明了,Array本身也是繼承自O(shè)bject的,那么Object的原型指向的是誰呢?
a.__proto__.__proto__.__proto__ === null // true // 等同于 Object.prototype.__proto__ === null
所以說,JavaScript中的對象,追根溯源都是來自一個(gè)null對象。佛曰:萬物皆空,善哉善哉。
除了使用.__proto__方式訪問對象的原型,還可以通過Object.getPrototypeOf方法來獲取對象的原型,以及通過Object.setPrototypeOf方法來重寫對象的原型。
值得注意的是,按照語言標(biāo)準(zhǔn),__proto__屬性只有瀏覽器才需要部署,其他環(huán)境可以沒有這個(gè)屬性,而且前后的兩根下劃線,表示它本質(zhì)是一個(gè)內(nèi)部屬性,不應(yīng)該對使用者暴露。因此,應(yīng)該盡量少用這個(gè)屬性,而是用 Object.getPrototypeof和Object.setPrototypeOf,進(jìn)行原型對象的讀寫操作。這里用__proto__屬性來描述對象中的原型,是因?yàn)檫@樣來得更加形象,且容易理解。
原型對象 prototype函數(shù)作為JavaScript中的一等公民,它既是函數(shù)又是對象,函數(shù)的原型指向的是Function.prototype
var Foo = function() {} Foo.__proto__ === Function.prototype // true
函數(shù)實(shí)例除了擁有__proto__屬性之外,還擁有prototype屬性。通過該函數(shù)構(gòu)造的新的實(shí)例對象,其原型指針__proto__會指向該函數(shù)的prototype屬性。
var a = new Foo(); a.__proto__ === Foo.prototype; // true
而函數(shù)的prototype屬性,本身是一個(gè)由Object構(gòu)造的實(shí)例對象。
Foo.prototype.__proto__ === Object.prototype; // true
prototype屬性很特殊,它還有一個(gè)隱式的constructor,指向了構(gòu)造函數(shù)本身。
Foo.prototype.constructor === Foo; // true a.constructor === Foo; // true a.constructor === Foo.prototype.constructor; // true
PS: a.constructor屬性并不屬于a(a.hasOwnProperty("constructor") === false),而是讀取的a.__proto__.constructor,所以上圖用虛線表示a.constructor,方便理解。
原型鏈概念:
原型鏈作為實(shí)現(xiàn)繼承的主要方法,其基本思想是利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法。
每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對象(prototype),原型對象都包含一個(gè)指向構(gòu)造函數(shù)的指針(constructor),而實(shí)例都包含一個(gè)指向原型對象的內(nèi)部指針(__proto__)。
那么,假如我們讓原型對象等于另一個(gè)類型的實(shí)例,此時(shí)的原型對象將包含一個(gè)指向另一個(gè)原型的指針,相應(yīng)地,另一個(gè)原型中也包含著一個(gè)指向另一個(gè)構(gòu)造函數(shù)的指針。假如另一個(gè)原型又是另一個(gè)類型的實(shí)例,那么上述關(guān)系依然成立。如此層層遞進(jìn),就構(gòu)造了實(shí)例與原型的鏈條,這就是原型鏈的基本概念。
意義:“原型鏈”的作用在于,當(dāng)讀取對象的某個(gè)屬性時(shí),JavaScript引擎先尋找對象本身的屬性,如果找不到,就到它的原型去找,如果還是找不到,就到原型的原型去找。以此類推,如果直到最頂層的Object.prototype還是找不到,則返回undefine。
親子鑒定在JavaScript中,也存在鑒定親子之間DNA關(guān)系的方法:
instanceof 運(yùn)算符返回一個(gè)布爾值,表示一個(gè)對象是否由某個(gè)構(gòu)造函數(shù)創(chuàng)建。
Object.isPrototypeOf() 只要某個(gè)對象處在原型鏈上,isProtypeOf都返回true
var Bar = function() {} var b = new Bar(); b instanceof Bar // true Bar.prototype.isPrototypeOf(b) // true Object.prototype.isPrototypeOf(Bar) // true
要注意,實(shí)例b的原型是Bar.prototype而不是Bar
一張歷史悠久的圖這是一張描述了Object、Function以及一個(gè)函數(shù)實(shí)例Foo他們之間原型之間聯(lián)系。如果理解了上面的概念,這張圖是不難讀懂。
從上圖中,能看到一個(gè)有趣的地方。
Function.prototype.__proto__ 指向了 Object.prototype,這說明Function.prototype 是一個(gè) Object實(shí)例,那么應(yīng)當(dāng)是先有的Object再有Function。
但是Object.prototype.constructor.__proto__ 又指向了 Function.prototype。這樣看來,沒有Function,Object也不能創(chuàng)建實(shí)例。
這就產(chǎn)生了一種類「先有雞還是先有蛋」的經(jīng)典問題,到底是先有的Object還是先有的Function呢?
這么哲學(xué)向的問題,留給你思考了。
我只是感慨:越往JavaScript的深處探索,越覺得這一門語言很哲學(xué)。
先有雞還是先有蛋?update on 2017/01/05
時(shí)隔半年,偶爾翻開這篇文章。
對于這個(gè)問題,又有了新的思考。
愿意跟能看到這里的你來分享一下。
我們可以先把 Object.prototype 和 Function.prototype 這兩個(gè)拎出來看,因?yàn)樗麄儽旧砭褪且粋€(gè)實(shí)例對象。
為方便理解,我們改一下名字,避免和 Object 和 Function 的強(qiáng)關(guān)聯(lián),分別叫:Op 和 Fp
那么就有這樣的原型鏈存在了
我再描述一下上面的原型鏈,先有 null , 再有了 Op , 然后再有了 Fp ,然后以 Fp 為原型的兩個(gè)構(gòu)造函數(shù) (Object, Function) 出現(xiàn)了。
而作為構(gòu)造函數(shù),需要有個(gè) prototype 屬性用來作為以該構(gòu)造函數(shù)創(chuàng)造的實(shí)例的繼承。
所以O(shè)bject.prototype = Op, Function.prototype = Fp。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/79804.html
摘要:設(shè)計(jì)模式是以面向?qū)ο缶幊虨榛A(chǔ)的,的面向?qū)ο缶幊毯蛡鹘y(tǒng)的的面向?qū)ο缶幊逃行┎顒e,這讓我一開始接觸的時(shí)候感到十分痛苦,但是這只能靠自己慢慢積累慢慢思考。想繼續(xù)了解設(shè)計(jì)模式必須要先搞懂面向?qū)ο缶幊?,否則只會讓你自己更痛苦。 JavaScript 中的構(gòu)造函數(shù) 學(xué)習(xí)總結(jié)。知識只有分享才有存在的意義。 是時(shí)候替換你的 for 循環(huán)大法了~ 《小分享》JavaScript中數(shù)組的那些迭代方法~ ...
摘要:繼承的是超類型中構(gòu)造函數(shù)中的屬性,如上繼承了屬性,但沒有繼承原型中的方法。上述造成的結(jié)果是子類型實(shí)例中有兩組超類型的構(gòu)造函數(shù)中定義的屬性,一組在子類型的實(shí)例中,一組在子類型實(shí)例的原型中。 ECMAScript只支持實(shí)現(xiàn)繼承,主要依靠原型鏈來實(shí)現(xiàn)。與實(shí)現(xiàn)繼承對應(yīng)的是接口繼承,由于script中函數(shù)沒有簽名,所以無法實(shí)現(xiàn)接口繼承。 一、原型鏈 基本思想:利用原型讓一個(gè)引用類型繼承另一個(gè)引用...
摘要:首先,需要來理清一些基礎(chǔ)的計(jì)算機(jī)編程概念編程哲學(xué)與設(shè)計(jì)模式計(jì)算機(jī)編程理念源自于對現(xiàn)實(shí)抽象的哲學(xué)思考,面向?qū)ο缶幊淌瞧湟环N思維方式,與它并駕齊驅(qū)的是另外兩種思路過程式和函數(shù)式編程。 JavaScript 中的原型機(jī)制一直以來都被眾多開發(fā)者(包括本人)低估甚至忽視了,這是因?yàn)榻^大多數(shù)人沒有想要深刻理解這個(gè)機(jī)制的內(nèi)涵,以及越來越多的開發(fā)者缺乏計(jì)算機(jī)編程相關(guān)的基礎(chǔ)知識。對于這樣的開發(fā)者來說 J...
摘要:對象重新認(rèn)識面向?qū)ο竺嫦驅(qū)ο髲脑O(shè)計(jì)模式上看,對象是計(jì)算機(jī)抽象現(xiàn)實(shí)世界的一種方式。除了字面式聲明方式之外,允許通過構(gòu)造器創(chuàng)建對象。每個(gè)構(gòu)造器實(shí)際上是一個(gè)函數(shù)對象該函數(shù)對象含有一個(gè)屬性用于實(shí)現(xiàn)基于原型的繼承和共享屬性。 title: JS對象(1)重新認(rèn)識面向?qū)ο? date: 2016-10-05 tags: JavaScript 0x00 面向?qū)ο?從設(shè)計(jì)模式上看,對象是...
摘要:封裝手寫的方筆記使用檢測文件前端掘金副標(biāo)題可以做什么以及使用中會遇到的坑。目的是幫助人們用純中文指南實(shí)現(xiàn)復(fù)選框中多選功能前端掘金作者緝熙簡介是推出的一個(gè)天挑戰(zhàn)。 深入理解 JavaScript Errors 和 Stack Traces - 前端 - 掘金譯者注:本文作者是著名 JavaScript BDD 測試框架 Chai.js 源碼貢獻(xiàn)者之一,Chai.js 中會遇到很多異常處理...
閱讀 2912·2021-11-25 09:43
閱讀 2338·2021-11-24 09:39
閱讀 2721·2021-09-23 11:51
閱讀 1414·2021-09-07 10:11
閱讀 1458·2019-08-27 10:52
閱讀 1946·2019-08-26 12:13
閱讀 3368·2019-08-26 11:57
閱讀 1405·2019-08-26 11:31