摘要:創建實例時無法向的構造函數傳遞參數在不影響所有對象實例的情況下易錯點添加原型方法的代碼要放在替換原型的語句之后。繼承屬性繼承方法原型式繼承原型式繼承并沒有使用嚴格意義上的構造函數。
許多OO 語言都支持兩種繼承方式:
接口繼承:只繼承方法簽名
實現繼承:繼承實際的方法。
由于函數沒有簽名,在ECMAScript 中無法實現接口繼承。ECMAScript 只支持實現繼承
原型鏈繼承原型鏈是Javascript實現繼承的主要方法
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; } function SubType(){ this.subproperty = false; } //繼承SuperType SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function(){ return this.subproperty; } var instance = new SubType(); console.log(instance.getSuperValue())//true //instanceof用于測試實例與原型鏈中出現過的構造函數的關系 console.log(instance instanceof object) //true console.log(instance instanceof SuperType) //true console.log(instance instanceof SubType) //true console.log(Object.prototype.isPrototypeof(instance)) //true console.log(SuperType.prototype.isPrototypeof(instance)) //true console.log(SubType.prototype.isPrototypeof(instance)) //true
實踐中較少多帶帶使用原型鏈繼承
注意:
instance.constructure現在指向的是SuperType
instance.toString現在指向的是Object.prototype
SuperType中的引用值類型會在所有SubType中共享。
創建SubType實例時,無法向SuperType的構造函數傳遞參數(在不影響所有對象實例的情況下)
易錯點
SubType、SuperType添加原型方法的代碼要放在替換原型的語句之后。否則SubType添加的原型方法會失效,因為原型對象被替換了。
不能通過字面量創建SubType的原型對象。因直接對原型賦值字面量對象會替換SubType的原型,打破了原型鏈。
借用構造函數繼承解決了Javascript原型鏈繼承中引用值類型被共享的問題
function SuperType(){ this.colors=["red","blue","green"]; } function SubType(){ SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push("black"); alert(instance1.colors);//"red,blue,green,black" var instance2 = new SubType(); alert(instance2.colors);//"red,blue,green"
通過call(this)或apply(this)我們再SubType的實例環境下調用了SuperType的構造函數,因此在SubType對象上執行了SuperType的對象初始化代碼,因此每個SubType都具有了自己的colors屬性
優勢
可以傳遞在子類構造函數中向超類構造函數傳遞參數
問題
因為方法都在構造函數中定義的,因此無法實現函數復用,每個對象都重新定義了一次方法。
無論什么情況下,都會調用兩次超類型構造函數:一次是在創建子類型原型的時候,另一次是在子類型構造函數內部。
注意
為了確保SuperType構造函數不會重寫子類屬性,應在調用SuperType的構造函數之后再添加子類自身的屬性。
組合繼承將原型鏈和借用構造函數組合到一塊,發揮二者之長的一種繼承模式。
原型鏈實現對屬性和方法的復用。
借用構造函數實現對實例屬性的繼承。
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ console.log(this.name); }; function SubType(name, age){ //繼承屬性 SuperType.call(this, name); this.age = age; } //繼承方法 SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){ console.log(this.age); }; var instance1 = new SubType("Nicholas", 29); instance1.colors.push("black"); console.log(instance1.colors); //"red,blue,green,black" instance1.sayName(); //"Nicholas"; instance1.sayAge(); //29 var instance2 = new SubType("Greg", 27); console.log(instance2.colors); //"red,blue,green" instance2.sayName(); //"Greg"; instance2.sayAge(); //27原型式繼承
原型式繼承并沒有使用嚴格意義上的構造函數。是借助原型可以基于已有的對象創建新對象,同時還不必因此創建自定義類型。
function object(o){ function F(){} F.prototype = o; return new F(); }
在object()函數內部,先創建了一個臨時性的構造函數,然后將傳入的對象作為這個構造函數的原型,最后返回了這個臨時類型的一個新實例。從本質上講,object()對傳入其中的對象執行了一次淺復制。
ECMAScript 5 通過新增Object.create()方法規范化了原型式繼承。這個方法接收兩個參數:
一個用作新對象原型的對象和(可選的)
一個為新對象定義額外屬性的對象。
在傳入一個參數的情況下,Object.create()與object()方法的行為相同。
Object.create()方法的第二個參數與Object.defineProperties()方法的第二個參數格式相同:每個屬性都是通過自己的描述符定義的。以這種方式指定的任何屬性都會覆蓋原型對象上的同名屬性。
在沒有必要興師動眾地創建構造函數,而只想讓一個對象與另一個對象保持類似的情況下,原型式繼承是完全可以勝任的。
創建一個僅用于封裝繼承過程的函數,該函數在內部以某種方式來增強對象,最后再像真地是它做了所有工作一樣返回對象
function createAnother(original){ //通過調用函數創建一個新對象,任何能夠返回新對象的函數都適用該模式 var clone = object(original); clone.sayHi = function(){ //以某種方式來增強這個對象 alert("hi"); }; return clone; //返回這個對象 } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = createAnother(person); anotherPerson.sayHi(); //"hi"
問題
無法做到函數復用而降低效率
寄生組合式繼承由于組合繼承兩次調用了SuperType的構造函數,SubType就具有了兩組SuperType的屬性:一組在實例上,一組在SubType 原型中。
寄生組合式繼承通過借用構造函數來繼承屬性,通過原型鏈的混成形式來繼承方法。
基本思路:不必為了指定子類型的原型而調用超類型的構造函數,我們所需要的無非就是超類型原型的一個副本而已。
本質:使用寄生式繼承來繼承超類型的原型,然后再將結果指定給子類型的原型。
function inheritPrototype(subType, superType){ var prototype = object(superType.prototype); //創建對象 prototype.constructor = subType; //增強對象 subType.prototype = prototype; //指定對象 } function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ SuperType.call(this, name); this.age = age; } inheritPrototype(SubType, SuperType); SubType.prototype.sayAge = function(){ alert(this.age); };
優勢
高效率:只調用了一次SuperType 構造函數,并且因此避免了在SubType.prototype 上面創建不必要的、多余的屬性。
原型鏈還能保持不變;因此,還能夠正常使用instanceof 和isPrototypeOf()
寄生組合式繼承是引用類型最理想的繼承范式。
YUI 的YAHOO.lang.extend()方法采用了寄生組合繼承,從而讓這種模式首次出現在了一個應用非常廣泛的JavaScript 庫中。
node中的util.inherits繼承寄生組合式繼承與寄生組合式繼承中inheritPrototype功能一致,因此如果不希望在子類間共享引用類型值屬性,還需組合借用構造函數繼承。
exports.inherits = function(ctor,superCtor){ ctor.super_ = superCtor; ctor.prototype = Object.create(superCtor.prototype,{ constructor:{ value:ctor, enumerable:false, writable:true, configurable:true } }; };
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/82552.html
摘要:和構造函數前面提到,是個內置隱藏屬性,雖然在可以通過訪問,但是其設計本意是不可被讀取和修改的,那么我們如何利用原型鏈來建立繼承關系提供了關鍵字。到這兒,思路就清晰了,怎么讓對象和對象的相連實現繼承只需把的構造函數的連接到就行了。 什么是繼承? 大多數人使用繼承不外乎是為了獲得這兩點好處,代碼的抽象和代碼的復用。代碼的抽象就不用說了,交通工具和汽車這類的例子數不勝數,在傳統的OO語言中(...
摘要:的繼承方式屬于原型式繼承,非常靈活。當使用關鍵字執行類的構造函數時,系統首先創建一個新對象,這個對象會繼承自構造函數的原型對象新對象的原型就是構造函數的屬性。也就是說,構造函數用來對生成的新對象進行一些處理,使這個新對象具有某些特定的屬性。 繼承這個東西在Javascript中尤其復雜,我掌握得也不好,找工作面試的時候在這個問題上栽過跟頭。Javascript的繼承方式屬于原型式繼承,...
摘要:中的繼承并不是明確規定的,而是通過模仿實現的。繼承中的繼承又稱模擬類繼承。將函數抽離到全局對象中,函數內部直接通過作用域鏈查找函數。這種范式編程是基于作用域鏈,與前面講的繼承是基于原型鏈的本質區別是屬性查找方式的不同。 這一節梳理對象的繼承。 我們主要使用繼承來實現代碼的抽象和代碼的復用,在應用層實現功能的封裝。 javascript 的對象繼承方式真的是百花齊放,屬性繼承、原型繼承、...
摘要:我們有了構造函數之后,第二步開始使用它構造一個函數。來個例子這種方式很簡單也很直接,你在構造函數的原型上定義方法,那么用該構造函數實例化出來的對象都可以通過原型繼承鏈訪問到定義在構造函數原型上的方法。 來源: 個人博客 白話解釋 Javascript 原型繼承(prototype inheritance) 什么是繼承? 學過面向對象的同學們是否還記得,老師整天掛在嘴邊的面向對象三大特...
摘要:這正是我們想要的太棒了毫不意外的,這種繼承的方式被稱為構造函數繼承,在中是一種關鍵的實現的繼承方法,相信你已經很好的掌握了。 你應該知道,JavaScript是一門基于原型鏈的語言,而我們今天的主題 -- 繼承就和原型鏈這一概念息息相關。甚至可以說,所謂的原型鏈就是一條繼承鏈。有些困惑了嗎?接著看下去吧。 一、構造函數,原型屬性與實例對象 要搞清楚如何在JavaScript中實現繼承,...
閱讀 2849·2021-11-22 11:56
閱讀 3553·2021-11-15 11:39
閱讀 898·2021-09-24 09:48
閱讀 759·2021-08-17 10:14
閱讀 1322·2019-08-30 15:55
閱讀 2753·2019-08-30 15:55
閱讀 1310·2019-08-30 15:44
閱讀 2775·2019-08-30 10:59