摘要:就是這個原理直接將某個對象直接賦值給構造函數的原型。五寄生式繼承重點創建一個僅用于封裝繼承過程的函數,該函數在內部以某種方式來增強對象,最后返回構造函數。
一、原型鏈繼承
重點:利用原型讓一個引用類型繼承另外一個引用類型的屬性和方法。構造函數,原型,實例之間的關系:每個構造函數都有一個原型對象,原型對象包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。
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 example = new SubType(); alert(example.getSuperValue());//true
使用原型創建對象會存在多個實例對引用類型的操作會被篡改的問題,在上面同樣存在這個問題,如下:
function SuperType(){ this.colors = ["red", "blue", "green"]; } function SubType(){}//即使沒有寫,也不會影響結果 SubType.prototype = new SuperType(); var example1 = new SubType(); example1.colors.push("black"); alert(example1.colors); //"red,blue,green,black" var example2 = new SubType(); alert(example.colors); //"red,blue,green,black"
兩個實例對象example1和example2的colors屬性指向相同,改變一個會影響另一個實例的屬性。
缺點:
①原型鏈繼承多個實例的引用類型屬性指向相同,一個實例修改了原型屬性,另一個實例的原型屬性也會被修改;
②不能傳遞參數;
③繼承單一。
重點:使用.call()和.apply()將父類構造函數引入子類函數,使用父類的構造函數來增強子類實例,等同于復制父類的實例給子類。
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } function SubType(name, age){ // 繼承自SuperType SuperType.call(this, name); this.age = age; } var example1 = new SubType("Mike", 23); example1.colors.push("black"); alert(example1.colors);//"red,blue,green,black" var example2 = new SubType(); alert(example2.colors);//"red,blue,green" alert(example1.name); // "Mike" alert(example1.age); // 23
借用構造函數繼承的重點就在于SuperType.call(this, name),調用了SuperType構造函數,這樣,SubType的每個實例都會將SuperType中的屬性復制一份。
缺點:
①只能繼承父類的實例屬性和方法,不能繼承原型屬性/方法;
②無法實現構造函數的復用,每個子類都有父類實例函數的副本,影響性能,代碼會臃腫。
重點:將原型鏈繼承和構造函數繼承這兩種模式的優點組合在一起,通過調用父類構造,繼承父類的屬性并保留傳參,然后通過將父類實例作為子類原型,實現函數復用。
其背后的思路是使用原型鏈實現對原型屬性和方法的繼承,而通過借用構造函數來實現對實例屬性的繼承,這樣,既通過在原型上定義方法實現了函數復用,又能保證每個實例都有它自己的屬性。
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; } // 繼承方法 SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){ alert(this.age); }; var example1 = new SubType("Mike", 23); example1.colors.push("black"); alert(example1.colors); //"red,blue,green,black" example1.sayName(); //"Mike"; example1.sayAge(); //23 var example2 = new SubType("Jack", 22); alert(example2.colors); //"red,blue,green" example2.sayName(); //"Jack"; example2.sayAge(); //22
缺陷:
父類中的實例屬性和方法既存在于子類的實例中,又存在于子類的原型中,不過僅是內存占用,因此,在使用子類創建實例對象時,其原型中會存在兩份相同的屬性/方法。-------這個方法是javascript中最常用的繼承模式。
重點:用一個函數包裝一個對象,然后返回這個函數的調用,這個函數就變成了個可以隨意增添屬性的實例或對象。object.create()就是這個原理,直接將某個對象直接賦值給構造函數的原型。
function object(obj){ function O(){} O.prototype = obj; return new O(); }
object()對傳入其中的對象執行了一次淺復制,將O的原型直接指向傳入的對象。
var person = { name: "Mike", friends: ["Jack", "Tom", "Joes"] }; var anotherPerson = object(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Peter"); var yetAnotherPerson = object(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("BoBo"); alert(person.friends); //"Jack,Tom,Joes,Peter,BoBo"
ECMAScript5通過新增Object.create()方法規范化了原型式繼承,這個方法接收兩個參數:一個用作新對象原型的對象和一個作為新對象定義額外屬性的對象。
var person = { name:"EvanChen", friends:["Shelby","Court","Van"]; }; var anotherPerson = Object.create(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = Object.create(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); console.log(person.friends);//"Shelby","Court","Van","Rob","Barbie"
缺點:
①原型鏈繼承多個實例的引用類型屬性指向相同(所有實例都會繼承原型上的屬性),存在篡改的可能;
②無法傳遞參數,無法實現復用。(新實例屬性都是后面添加的)。
重點:創建一個僅用于封裝繼承過程的函數,該函數在內部以某種方式來增強對象,最后返回構造函數。(就像給原型式繼承外面套了個殼子,然后return出來)
function createAnother(original){ varclone=object(original); // 過調用函數創建一個新對象 clone.sayHi = function(){ // 以某種方式增強這個對象 alert("hi"); }; return clone; // 返回對象 }
函數的主要作用是為構造函數新增屬性和方法,以增強函數。
var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = createAnother(person); anotherPerson.sayHi(); //"hi"
缺點:
①原型鏈繼承多個實例的引用類型屬性指向相同,存在篡改的可能;
②無法傳遞參數,沒用到原型,無法復用。
重點:通過借用構造函數傳遞參數和寄生模式實現繼承屬性,通過原型鏈的混成形式來繼承方法,在函數中用apply或者call引入另一個構造函數,可傳參。
function inheritPrototype(subType, superType){ var prototype = Object.create(superType.prototype); //Object.create創建對象 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); } var example1 = new SubType("abc", 21); var example2 = new SubType("def", 22); example1.colors.push("pink"); // ["red", "blue", "green", "pink"] example1.colors.push("black"); // ["red", "blue", "green", "black"]
寄生組合繼承集合了前面幾種繼承優點,幾乎避免了上面繼承方式的所有缺陷,是執行效率最高也是應用面最廣的。
缺點:
實現的過程相對繁瑣。
為什么要學習這些繼承方式,明明可以直接繼承為什么還要搞這么麻煩?主要是為了學習它們的思想,打下更好的基礎,為以后閱讀框架源碼,或自己封裝組件甚至框架大有益處。
時間有點匆忙,沒有加上ES6的extends,有空再補上。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/97293.html
摘要:組合繼承也是需要修復構造函數指向的這種方式融合原型鏈繼承和構造函數的優點,是中最常用的繼承模式。的繼承機制完全不同,實質是先將父類實例對象的屬性和方法,加到上面所以必須先調用方法,然后再用子類的構造函數修改。 前言 面向對象編程很重要的一個方面,就是對象的繼承。A 對象通過繼承 B 對象,就能直接擁有 B 對象的所有屬性和方法。這對于代碼的復用是非常有用的。 大部分面向對象的編程語言,...
摘要:組合繼承也是需要修復構造函數指向的這種方式融合原型鏈繼承和構造函數的優點,是中最常用的繼承模式。的繼承機制完全不同,實質是先將父類實例對象的屬性和方法,加到上面所以必須先調用方法,然后再用子類的構造函數修改。 前言 面向對象編程很重要的一個方面,就是對象的繼承。A 對象通過繼承 B 對象,就能直接擁有 B 對象的所有屬性和方法。這對于代碼的復用是非常有用的。 大部分面向對象的編程語言,...
摘要:組合繼承也是需要修復構造函數指向的這種方式融合原型鏈繼承和構造函數的優點,是中最常用的繼承模式。的繼承機制完全不同,實質是先將父類實例對象的屬性和方法,加到上面所以必須先調用方法,然后再用子類的構造函數修改。 前言 面向對象編程很重要的一個方面,就是對象的繼承。A 對象通過繼承 B 對象,就能直接擁有 B 對象的所有屬性和方法。這對于代碼的復用是非常有用的。 大部分面向對象的編程語言,...
摘要:組合繼承也是需要修復構造函數指向的這種方式融合原型鏈繼承和構造函數的優點,是中最常用的繼承模式。的繼承機制完全不同,實質是先將父類實例對象的屬性和方法,加到上面所以必須先調用方法,然后再用子類的構造函數修改。 前言 面向對象編程很重要的一個方面,就是對象的繼承。A 對象通過繼承 B 對象,就能直接擁有 B 對象的所有屬性和方法。這對于代碼的復用是非常有用的。 大部分面向對象的編程語言,...
摘要:對象經典對象創建與繼承模式組合模式創建對象中創建一個對象的方式多種多樣,每種方式都有自己缺點或者優點,具體的可以參考而組合使用構造函數模式和原型模式來創建自定義類型算是最常見的方式了。 title: JS對象(3)經典對象創建與繼承模式 date: 2016-09-28 tags: JavaScript 0x01 組合模式創建對象 JS 中創建一個對象的方式多種多樣,...
閱讀 3497·2019-08-30 15:53
閱讀 3410·2019-08-29 16:54
閱讀 2198·2019-08-29 16:41
閱讀 2407·2019-08-23 16:10
閱讀 3382·2019-08-23 15:04
閱讀 1353·2019-08-23 13:58
閱讀 352·2019-08-23 11:40
閱讀 2458·2019-08-23 10:26