這篇原本應該是做爲寫JS
面向對象的前奏,只是做爲《javascript高級程序設計》繼承一章的筆記javascript
原型鏈java
code
實現shell
function SuperType() { this.colors = ['red','blue', 'green']; } function SubType() { } SubType.prototype = new SuperType(); var instance1 = new SubType(); instance1.colors.push("black"); console.log(instance1.colors); // ['red','blue', 'green','black'] var instance2 = new SubType(); console.log(instance2.colors); // ['red','blue', 'green','black'] var instance = new SuperType(); console.log(instance.colors); // ['red','blue', 'green']
借用構造函數segmentfault
code
實現繼承函數
function SuperType() { this.colors = ["red","blue","green"]; } function SubType() { SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push("black"); console.log(instance1.colors); // ["red", "blue", "green", "black"] var instance2 = new SubType(); console.log(instance2.colors); // ["red", "blue", "green"] var instance = new SuperType(); console.log(instance.colors); // ['red','blue', 'green']
一樣也能夠實現參數的傳遞this
function SuperType(name) { this.name = name; } function SubType(){ SuperType.call(this, "jack"); this.age = 29; } var instance = new SubType(); console.log(instance.name); // jack console.log(instance.age); // 29
組合繼承prototype
code
實現設計
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.sayAge = function(){ console.log(this.age); }; var instance1 = new SubType("jack", 29); instance1.colors.push("black"); console.log(instance1.colors); //["red", "blue", "green", "black"] instance1.sayName(); // jack instance1.sayAge(); // 29 var instance2 = new SubType("allen", 23); console.log(instance2.colors); // ["red", "blue", "green"] instance2.sayName(); //allen instance2.sayAge(); // 23
instanceOf
和isPrototypeOf
也可以用於識別基於組合繼承建立的對象原型式繼承code
沒有嚴格意義上的構造函數,經過藉助原型,能夠基於已有的對象建立新對象,同時還沒必要所以建立自定義類型對象
function object(o){ function F(){}; F.prototype = o; return new F(); }
在object()
函數內部,先建立了一個臨時性的構造函數,而後將傳入的對象做爲這個構造函數的原型,最後返回這個臨時類型的一個新實例。從本質上將,object()
對傳入其中的對象執行了一次淺複製
function object(o) { function F() {}; F.prototype = o; return new F(); } var person = { name:'jack', friends:['allen','lucy','van'] } var anotherPerson = object(person); anotherPerson.name = 'bob'; anotherPerson.friends.push('steve'); var yetAnotherPerson = object(person); yetAnotherPerson.name = 'linda'; yetAnotherPerson.friends.push('shelly') console.log(person.friends); //["allen", "lucy", "van", "steve", "shelly"]
這種原型式繼承,要求你必須有一個對象能夠做爲另外一個對象的基礎。若是有這麼一個對象的話,能夠把他傳遞給object()
函數,而後再根據具體需求對獲得的對象加以修飾便可。
ECMAScript5
經過Object.create()
方法規範花了原型式繼承。這個方法接受兩個參數:一個用做新對象原型的對象和(可選的)一個爲新對象定義額外屬性的對象。在傳入一個參數的狀況下,Object,create()
與object()
函數方法的行爲相同
在沒有必要建立構造函數,而只是想讓一個對象與另外一個對象保持相似的狀況下,原型式繼承是徹底能夠勝任的。不過,包含引用類型值的屬性始終都會共享響應的值,就像使用原型模式同樣
寄生式繼承
寄生式繼承是與原型式繼承緊密相關的一種思路。寄生式繼承的思路與寄生構造函數和工廠模式相似,即建立一個僅用於封裝繼承過程的函數,該函數在內部已某種方式來加強對象,最後再像真的是它作了全部工做同樣返回對象。
function createAnother(original){ var clone = object(original); // 經過調用 object() 函數建立一個新對象 clone.sayHi = function(){ // 以某種方式來加強對象 alert("hi"); }; return clone; // 返回這個對象 }
object()
函數不是必需的;任何可以返回新對象的函數都使用與此模式。寄生組合式繼承
JavaScript
最經常使用的繼承模式;不過也有本身的不足。組合繼承最大的問題就是不管什麼狀況下,都會調用兩次父類的構造函數:一次是在建立子類原型的時候,另外一次是在子類構造函數內部。子類最終會包含父類對象的所有實例屬性,但咱們不得不在調用子類構造函數時重寫這些屬性。
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); // 第二次調用 SuperType() this.age = age; } SubType.prototype = new SuperType(); // 第一次調用 SuperType() SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function() { console.log(this.age); };
第一次調用SuperType
構造函數時,SubType.prototype
會獲得兩個屬性:name
和colors
,他們都是SuperType
的實例屬性,只不過如今位於SubType
的原型中。當調用SubType
構造函數時,又會調用一次SuperType
構造函數,這一次又在新對象上建立了實例屬性name
和colors
。 因而,這兩個屬性就屏蔽了原型中的兩個同名屬性。
所謂寄生組合式繼承,即經過借用構造函數來繼承屬性,經過原型鏈的混成形式來繼承方法。其背後的基本思路是:沒必要爲了指定子類的原型而調用父類的構造函數,咱們所須要的無非就是父類原型的一個副本而已。本質上,就是使用寄生式繼承來繼承父類型的原型,而後再將結果指定給子類的原型。寄生組合式繼承的基本模式以下
function inheritPrototype(subType, superType) { var prototype = object(superType.prototype); prototype.constructor = subType; subType.prototype = prototype; }
第一步是建立父類原型的一個副本,第二步是爲建立的副本添加constructor
屬性,從而彌補因重寫原型而失去的默認的constructor
屬性。第三步是將新建立的對象(即副本)賦值給子類的原型。
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); // 第二次調用 SuperType() this.age = age; } inheritPrototype(SubType, SuperType) SubType.prototype.sayAge = function() { console.log(this.age); };
這個例子的高效率體如今它只調用了一次SuperType
構造函數,而且所以避免了在SubType.prototype
上建立沒必要要的、多餘的屬性。於此同時,原型鏈還能保持不變;所以,還可以正常使用instanceof
和isPrototypeOf()
。開發人員廣泛認爲寄生組合繼承是引用類型最理想的繼承範式。
constructor
屬性,從而彌補因重寫原型而失去的默認的constructor
屬性。第三步是將新建立的對象(即副本)賦值給子類的原型。
JS
面向對象系列