1. 程式人生 > 其它 >javaScript實現繼承的幾種方法

javaScript實現繼承的幾種方法

很多面向物件的語言都接受兩種繼承:介面繼承和實現繼承。

前者只繼承方法簽名,後者繼承實際的方法。介面繼承在 ECMAScript 中是不可能的,因為函式沒有籤 名。實現繼承是 ECMAScript 唯一支援的繼承方式,而這主要是通過原型鏈實現的。 1.原型鏈繼承 通過原型鏈繼承的方式,SubType可以繼承SuperType建構函式上的所有屬性(自定義的屬性&&原型鏈上的屬性)
    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; }; let instance = new SubType(); console.log(instance);

問題:1.當原型鏈中包含引用型別的時候,會在所有例項間共享

2.原型鏈的第二個問題是,子型別在例項化時不能給父型別的建構函式傳參。

2.盜用建構函式

apply()和 call()方法以新建立的物件為上下文執行建構函式 解決了原型鏈繼承中出現引用型別不能在例項間共享的問題
function SuperType() { 
 this.colors = ["red", "blue", "green"]; 
} 
function SubType() { 
 // 繼承 SuperType 
 SuperType.call(this); 
} 
let instance1 = new SubType(); 
instance1.colors.push(
"black"); console.log(instance1.colors); // "red,blue,green,black" let instance2 = new SubType(); console.log(instance2.colors); // "red,blue,green"

並且使用該種方式,也可以解決原型鏈上不能傳參的問題

function SuperType(name){ 
 this.name = name; 
} 
function SubType() { 
 // 繼承 SuperType 並傳參
 SuperType.call(this, "Nicholas"); 
 // 例項屬性
 this.age = 29; 
} 
let instance = new SubType(); 
console.log(instance.name); // "Nicholas";

問題: 1.必須在建構函式中宣告方法,不能重用 2.子類不能訪問父類上面的原型方法

3.組合繼承

組合繼承通過建構函式的方式繼承例項屬性,通過原型鏈繼承的方式繼承屬性和方法,可以讓屬性在例項間私有,同時可以通過原型鏈繼承的方式實現方法間的共享

組合繼承彌補了原型鏈和盜用建構函式的不足,是 JavaScript 中使用最多的繼承模式。而且組合繼承也保留了 instanceof 操作符和 isPrototypeOf()方法識別合成物件的能力。
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); 
}; 
let instance1 = new SubType("Nicholas", 29); 
instance1.colors.push("black"); 
console.log(instance1.colors); // "red,blue,green,black" 
instance1.sayName(); // "Nicholas"; 
instance1.sayAge(); // 29 
let instance2 = new SubType("Greg", 27); 
console.log(instance2.colors); // "red,blue,green" 
instance2.sayName(); // "Greg"; 
instance2.sayAge(); // 27

4.原型式繼承

原型式繼承非常適合不需要單獨建立建構函式,但仍然需要在物件間共享資訊的場合。屬性中包含的引用值始終會在相關物件間共享,跟使用原型模式是一樣的。
function object(o) { 
 function F() {} 
 F.prototype = o; 
 return new F(); 
}
let person = { 
 name: "Nicholas", 
 friends: ["Shelby", "Court", "Van"] 
}; 
let anotherPerson = object(person); 
anotherPerson.name = "Greg"; 
anotherPerson.friends.push("Rob"); 
let yetAnotherPerson = object(person); 
// let yetAnotherPerson = Object.create(person);
// 這裡的Object.create方法等同於object方法
yetAnotherPerson.name = "Linda"; 
yetAnotherPerson.friends.push("Barbie"); 
console.log(person.friends); // "Shelby,Court,Van,Rob,Barbie"

5.寄生式繼承

建立一個實現繼承的函式,以某種方式增強物件,然後返回這個物件
function createAnother(original){ 
 let clone = object(original); // 通過呼叫函式建立一個新物件
 clone.sayHi = function() { // 以某種方式增強這個物件
 console.log("hi"); 
 }; 
 return clone; // 返回這個物件
}
let person = { 
 name: "Nicholas", 
 friends: ["Shelby", "Court", "Van"] 
}; 
let anotherPerson = createAnother(person); 
anotherPerson.sayHi(); // "hi"

6.寄生式組合繼承

function inheritPrototype(subType, superType) { 
 let 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() { 
 console.log(this.name); 
}; 
function SubType(name, age) { 
 SuperType.call(this, name);
 this.age = age; 
} 
inheritPrototype(SubType, SuperType); 
SubType.prototype.sayAge = function() { 
 console.log(this.age); 
};

7.extends

ES6 類支援單繼承。使用 extends 關鍵字,就可以繼承任何擁有[[Construct]]和原型的物件 在類建構函式中使用 super 可以呼叫父類建構函式。 如果在派生類中顯式定義了建構函式,則要麼必須在其中呼叫super(),要麼必須在其中返回一個物件。
class Vehicle {} 
// 繼承類
class Bus extends Vehicle {} 
let b = new Bus(); 
console.log(b instanceof Bus); // true 
console.log(b instanceof Vehicle); // true 
function Person() {} 
// 繼承普通建構函式
class Engineer extends Person {} 
let e = new Engineer(); 
console.log(e instanceof Engineer); // true 
console.log(e instanceof Person); // true