摘要:操作符構(gòu)造步驟有三步構(gòu)造一個類的實例這個實例是一個空對象,并且他的屬性指向構(gòu)造函數(shù)的原型。不優(yōu)化原生的或自定義的作為構(gòu)造函數(shù)是及其不高效的。
原文地址:Javascript – How Prototypal Inheritance really works
在網(wǎng)上可以看到各種關(guān)于Javascript原型繼承的文章,但Javascript規(guī)范中只提供了new操作符這一種實現(xiàn)原型繼承的方法。因此網(wǎng)上大多數(shù)的文章是具有迷惑性的,很混亂。這篇文章會讓你清晰的認識到什么是真正的原型繼承?并且怎么樣使用它?
原型繼承的定義:你會經(jīng)常看到如下關(guān)于原型繼承的定義:
訪問一個對象屬性的時候,Javascript會沿著原型鏈向上尋找,直到找到該屬性。
Javascript中大多數(shù)實現(xiàn)方式都是使用__proto__來指定原型鏈中下一個被訪問的對象,接下來會揭示__proto__與prototype之間的區(qū)別。
注意:不要在你的代碼中使用__proto__,文中使用它僅僅是為了更好的解釋Javascript繼承是如何工作的。
下面的代碼展示了Javascript引擎如何檢索對象的屬性(偽代碼,僅為了方便理解)
function getProperty(obj, prop) { if (obj.hasOwnProperty(prop)){ return obj[prop]; }else if (obj.__proto__ !== null){ return getProperty(obj.__proto__, prop); }else{ return undefined; } }
舉個例子:一個二維的點。擁有x坐標(biāo)屬性,y坐標(biāo)屬性和一個print方法。
用書面語言來表示該定義就是:我們定義了一個有三個屬性的對象:x,y和print。為了構(gòu)造一個新點,我們只需要創(chuàng)建一個對象并將他的__proto__屬性指向Point。
var Point = { x: 0, y: 0, print: function () { console.log(this.x, this.y); } }; var p = {x: 10, y: 20, __proto__: Point}; p.print(); // 10 20奇怪的原型繼承:
怪異之處在于解釋原型繼承的人給出的例子往往與他們的定義不相符合,他們給出的代碼通常如下所示:
function Point(x, y) { this.x = x; this.y = y; } Point.prototype = { print: function () { console.log(this.x, this.y); } }; var p = new Point(10, 20); p.print(); // 10 20
上面所例舉的代碼跟原型繼承完全不相關(guān),Point是構(gòu)造函數(shù),它有一個prototype屬性,使用了new操作符,但是然后呢?
new是如何工作的:Brendan Eich 想讓javascript像Java,C++這些傳統(tǒng)的面向?qū)ο笳Z言一樣,用new操作類直接構(gòu)造一個實例,所以他給Javascript也添了new操作符。
C++中有構(gòu)造函數(shù),用來初始化實例的屬性。因此,new操作符操作的對象必須是函數(shù)。
我們需要把對象的方法掛載到某個地方,由于我們使用的是原型語言,我們把他放在函數(shù)的原型屬性里。
new操作符構(gòu)造步驟有三步:構(gòu)造一個類的實例:這個實例是一個空對象,并且他的__proto__屬性指向構(gòu)造函數(shù)的原型。
初始化實例:構(gòu)造函數(shù)被調(diào)用,并將this指向這個實例。
返回實例對象。
現(xiàn)在我們了解了new構(gòu)造的過程,我們在Javascript中實現(xiàn)它:
function New (f) { var n = { "__proto__": f.prototype }; return function () { f.apply(n, arguments); return n; }; }
舉一個小例子:
function Point(x, y) { this.x = x; this.y = y; } Point.prototype = { print: function () { console.log(this.x, this.y); } }; var p1 = new Point(10, 20); p1.print(); // 10 20 console.log(p1 instanceof Point); // true var p2 = New (Point)(10, 20); p2.print(); // 10 20 console.log(p2 instanceof Point); // trueJavascript中真正的原型繼承:
Javascript規(guī)范只定義了new操作符的工作流程,Douglas Crockford發(fā)現(xiàn)了一種利用new實現(xiàn)原型繼承的新方法,他寫的Object.create函數(shù)。
Object.create = function (parent) { function F() {} F.prototype = parent; return new F(); };
看起來很奇怪,但實際上很簡潔。他只創(chuàng)建了一個新的對象,原型你可以隨意設(shè)置。如果允許使用__proto__的話,這個例子可以這樣寫:
Object.create = function (parent) { return { "__proto__": parent }; };
下面這個Point例子才是真正的原型繼承。
var Point = { x: 0, y: 0, print: function () { console.log(this.x, this.y); } }; var p = Object.create(Point); p.x = 10; p.y = 20; p.print(); // 10 20結(jié)論:
我們了解了原型繼承并用一種具體的方法實現(xiàn)了它。但這樣寫有一些缺點:
不標(biāo)準(zhǔn):__proto__不是標(biāo)準(zhǔn)并不贊成使用, 并且原生的 Object.create 和 Douglas Crockford的實現(xiàn)不等同。
不優(yōu)化:Object.create (原生的或自定義的)作為構(gòu)造函數(shù)是及其不高效的。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/78942.html
摘要:然而,對象字面量不是真正意義上的哈希映射,如果使用不當(dāng)可能會構(gòu)成潛在的隱患。空對象創(chuàng)建一個真正的哈希映射的秘訣就是避免原型,及其帶來的包袱。在此之前,甚至之后,你應(yīng)該使用空對象滿足你所有的基本哈希映射需求。 在JavaScript中存儲鍵值對的一個簡單常見的方法是使用對象字面量。然而,對象字面量不是真正意義上的哈希映射,如果使用不當(dāng)可能會構(gòu)成潛在的隱患。雖然目前JavaScrip...
摘要:使用構(gòu)造函數(shù)的原型繼承相比使用原型的原型繼承更加復(fù)雜,我們先看看使用原型的原型繼承上面的代碼很容易理解。相反的,使用構(gòu)造函數(shù)的原型繼承像下面這樣當(dāng)然,構(gòu)造函數(shù)的方式更簡單。 五天之前我寫了一個關(guān)于ES6標(biāo)準(zhǔn)中Class的文章。在里面我介紹了如何用現(xiàn)有的Javascript來模擬類并且介紹了ES6中類的用法,其實它只是一個語法糖。感謝Om Shakar以及Javascript Room中...
摘要:避免脆弱的基類問題。紅牌警告沒有提到上述任何問題。單向數(shù)據(jù)流意味著模型是單一的事實來源。單向數(shù)據(jù)流是確定性的,而雙向綁定可能導(dǎo)致更難以遵循和理解的副作用。原文地址 1. 你能說出兩種對 JavaScript 應(yīng)用開發(fā)者而言的編程范式嗎? 希望聽到: 2. 什么是函數(shù)編程? 希望聽到: 3. 類繼承和原型繼承的不同? 希望聽到 4. 函數(shù)式編程和面向?qū)ο缶幊痰膬?yōu)缺點? ...
摘要:忍者級別的函數(shù)操作對于什么是匿名函數(shù),這里就不做過多介紹了。我們需要知道的是,對于而言,匿名函數(shù)是一個很重要且具有邏輯性的特性。通常,匿名函數(shù)的使用情況是創(chuàng)建一個供以后使用的函數(shù)。 JS 中的遞歸 遞歸, 遞歸基礎(chǔ), 斐波那契數(shù)列, 使用遞歸方式深拷貝, 自定義事件添加 這一次,徹底弄懂 JavaScript 執(zhí)行機制 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機制,如果...
摘要:函數(shù)式編程前端掘金引言面向?qū)ο缶幊桃恢币詠矶际侵械闹鲗?dǎo)范式。函數(shù)式編程是一種強調(diào)減少對程序外部狀態(tài)產(chǎn)生改變的方式。 JavaScript 函數(shù)式編程 - 前端 - 掘金引言 面向?qū)ο缶幊桃恢币詠矶际荍avaScript中的主導(dǎo)范式。JavaScript作為一門多范式編程語言,然而,近幾年,函數(shù)式編程越來越多得受到開發(fā)者的青睞。函數(shù)式編程是一種強調(diào)減少對程序外部狀態(tài)產(chǎn)生改變的方式。因此,...
閱讀 1692·2021-11-23 09:51
閱讀 3209·2021-09-26 10:21
閱讀 807·2021-09-09 09:32
閱讀 889·2019-08-29 16:06
閱讀 3318·2019-08-26 13:36
閱讀 781·2019-08-26 10:56
閱讀 2573·2019-08-26 10:44
閱讀 1153·2019-08-23 14:04