javaScript實現繼承的幾種方法
阿新 • • 發佈:2021-09-04
很多面向物件的語言都接受兩種繼承:介面繼承和實現繼承。
前者只繼承方法簽名,後者繼承實際的方法。介面繼承在 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