摘要:由于原型即本身也是對象,所以原型繼承可認為是一種特殊的對象式繼承。原型繼承里的原型即是函數的特有屬性,原型繼承事先得有函數。揭秘魔術箱不論原型繼承還是對象式繼承,其核心技術是實現了對象實例的鏈。
JavaScript的原型繼承是老生常談。由于原型即prototype本身也是對象,所以“原型”繼承可認為是一種特殊的“對象式”繼承。”對象式“繼承是筆者基于自己的理解,所提出的一個名詞。本文就著重闡述這兩種繼承方式的異同之處。
原型繼承JavaScript里的原型即prototype是函數的特有屬性,原型繼承事先得有函數。
// 定義函數Foo function Foo(name) { this.name = name; } // 定義Foo的原型 Foo.prototype.say = function() { console.log(this.name, "say"); }
函數及其原型定義好了,就可以使用原型繼承了。
var foo = new Foo("foo"); foo.say() //foo say foo instanceof Foo; //true。 foo 是Foo的一個實例 foo.__proto__ === Foo.prototype // true
上面用的是new操作符,它實際是通過Object.create工作,其過程如下。所以new其實是Object.create的便利操作方式。
var foo = Object.create(Foo.prototype); foo.name = "foo" foo.say(); foo instanceof Foo; //true。 foo 是Foo的一個實例 foo.__proto__ === Foo.prototype // true
請打起精神,Object.create(...)接受一個函數原型即object實例,以此實例為“模型”,創建新的object實例。新object實例的__proto__指向前function的prototype,自此新object實例也就擁有了前function prototype的字段和方法。
既然Foo.prototype本身是object實例,那么我們是否可以給Object.create(...)傳入一個普通的object實例呢?答案是可以的。這就是本文所要表述的“對象式”繼承。
“對象式“繼承開門見山地用code來說明:
// 創建對象實例Foo var Foo = { name: "foo", say: function() { console.log(this.name, "say"); } } // 以Foo為“模型”,創建新的對象實例foo var foo = Object.create(Foo); foo.__proto__ == Foo;// true // 所以foo也會擁有Foo的字段和方法,這點與原型繼承類似。 foo.say(); // foo say. // 但是foo不是Foo的實例。 foo instanceof Foo; // TypeError: Right-hand side of "instanceof" is not callable
如果Foo是個函數,結果基本是相同的,除了instanceof Foo 會等于false。
function Foo() { } Foo.say = function() { console.log(Foo.name, "say"); } // 以Foo為“模型”,創建新的對象實例foo var foo = Object.create(Foo); foo.__proto__ == Foo;// true // 所以foo也會擁有Foo的字段和方法,這點與原型繼承類似。 foo.say(); // Foo say. // 但是foo不是Foo的實例。 foo instanceof Foo; // false“對象式”繼承的一個應用
舉個不太恰當的例子,如果我們需要對Math.abs做些“修正”,對于在-1和1之間的數值保持原值。
var MMath = Object.create(Math); MMath.abs = function(val) { if (val >= -1 && val <=1) { return val; } return MMath.__proto__.abs(val); } MMath.abs(0.5) // 0.5 MMath.abs(-0.5) // -0.5 MMath.abs(-2) // 2揭秘Object.create魔術箱
不論原型繼承還是“對象式”繼承,其核心技術是Object.create(...)實現了對象實例的__proto__鏈。我們做個簡單的實現:
Object.myCreate = function(obj) { if (obj instanceof Object || obj === null) { var newObj = {}; Object.setPrototypeOf(newObj, obj) return newObj; } else { throw "error happens. Should input a object"; } }
function Fooo() {} Fooo.say = function() { console.log(Fooo.name, "say"); } var myFooo = Object.myCreate(Fooo); myFooo.say(); // Fooo say
自此我們了解了Object.create(...)的黑魔法,也有助于我們理解Object.create({})和Oject.create(null)的區別,就是前者的__proto__是個object實例,擁有toString等方法。后者的__proto__是null,它不具有任何方法。在特別注重效率的情景,后者具有優勢。
總結本文提出“對象式”繼承的概念,并與原型繼承對比,闡述其區別和聯系,希望有助于深化理解。雖然ES6越來越廣泛應用了,了解函數原型等這些ES3/ES5的概念應該是有助于JS的深入學習。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/84741.html
摘要:面向對象實現代碼動物發聲汪汪喵喵調用代碼動物發聲喵喵動物發聲汪汪當要增加一種動物時,只需增加一個繼承,不會影響其他已有的動物邏輯。所以的繼承和的原型繼承,可謂殊途同歸。 傳統面向對象的繼承和多態 我們知道C++/Java/C#等面向對象語言,都原生地支持類的繼承。繼承的核心作用大抵是創建一個派生類,并使其復用基本類(即父類)的字段和/或方法。并且派生類可以重寫基本類的方法。這樣基本類和...
摘要:從運行結果可以看出,當子類繼承多個父類的時候,對于構造函數,只有第一個能夠被繼承,第二個就等掉了。重點看,類繼承了,同時,在構造函數中自己做了規定,也就是的構造函數是按照的意愿執行,不執行的內容,但是,還有一個方法,則繼承了這個方法。 在上一講代碼的基礎上,做進一步修改,成為了如下程序,請看官研習這個程序: #!/usr/bin/env python #coding:utf-8 c...
摘要:的內存分配方式修飾變量通常情況下,變量有個地方可以賦值直接賦值,構造函數中,或是初始化塊中。如就是對于變量,在聲明時,如果你沒有賦值,系統默認這是一個空白域,在構造函數進行初始化,如果是靜態的,則可以在初始化塊。 【java中為什么會有final變量】: final這個關鍵字的含義是這是無法改變的或者終態的; 那么為什么要阻止改變呢? java語言的發明者可能由于兩個目的而阻止改變: ...
摘要:在面向對象的程序設計語言中,多態是繼數據抽象和繼承之后的第三種基本特征。 在面向對象的程序設計語言中,多態是繼數據抽象和繼承之后的第三種基本特征。 1.再論向上轉型 多態作用:消除類型之間的耦合關系. 2.轉機 綁定:將一個方法調用同一個方法主體關聯起來. 前期綁定:在程序執行前就進行綁定(面向過程語言默認綁定方式). 后期綁定:也叫動態綁定或運行時綁定,在運行時根據對象的類型進行綁...
摘要:這正是我們想要的太棒了毫不意外的,這種繼承的方式被稱為構造函數繼承,在中是一種關鍵的實現的繼承方法,相信你已經很好的掌握了。 你應該知道,JavaScript是一門基于原型鏈的語言,而我們今天的主題 -- 繼承就和原型鏈這一概念息息相關。甚至可以說,所謂的原型鏈就是一條繼承鏈。有些困惑了嗎?接著看下去吧。 一、構造函數,原型屬性與實例對象 要搞清楚如何在JavaScript中實現繼承,...
閱讀 917·2021-11-24 09:38
閱讀 925·2021-11-23 09:51
閱讀 2939·2021-11-16 11:44
閱讀 1762·2021-09-22 15:52
閱讀 1626·2021-09-10 11:20
閱讀 1361·2019-08-30 13:47
閱讀 1292·2019-08-29 12:36
閱讀 3293·2019-08-26 10:43