前端繼承方式彙總

1 原型鏈繼承

核心:讓子類的原型指向父類的實例函數

ChildType.prototype = new ParentType() // 全部涉及到原型鏈繼承的繼承方式都要修改子類構造函數的指向,不然子類實例的構造函數會指向PerentType。
ChildType.prototype.constructor =ChildType;

優勢:父類方法能夠複用
缺點:性能

  • 父類的引用屬性會被全部子類實例共享
  • 子類構建實例時不能向父類傳遞參數

2 .構造函數繼承

核心:將父類構造函數的內容複製給了子類的構造函數。這是全部繼承中惟一一個不涉及到prototype的繼承。this

ParentType.call(ChildType);

優勢:和原型鏈繼承徹底反過來。spa

  • 父類的引用屬性不會被共享
  • 子類構建實例時能夠向父類傳遞參數

缺點:父類的方法不能複用,子類實例的方法每次都是單首創建的。prototype

3 .組合繼承

核心:原型式繼承和構造函數繼承的組合,兼具了兩者的優勢。code

function ParentType() { this.name = 'parent'; this.arr = [1, 2, 3]; }
ParentType.prototype.say = function() { console.log('this is parent') }
function ChildType() {
ParentType.call(this)
// 第二次調用ParentType
}
ChildType.prototype
= new ParentType() // 第一次調用ParentType
 
 

優勢:對象

  • 父類的方法能夠被複用
  • 父類的引用屬性不會被共享
  • 子類構建實例時能夠向父類傳遞參數

缺點:
調用了兩次父類的構造函數,第一次給子類的原型添加了父類的name, arr屬性,第二次又給子類的構造函數添加了父類的name, arr屬性,從而覆蓋了子類原型中的同名參數。這種被覆蓋的狀況形成了性能上的浪費。blog

4 原型式繼承

核心:原型式繼承的object方法本質上是對參數對象的一個淺複製。
優勢:父類方法能夠複用
缺點:繼承

  • 父類的引用屬性會被全部子類實例共享
  • 子類構建實例時不能向父類傳遞參數
function object(o){ function F(){} F.prototype = o; return new F(); } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = object(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = object(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"

上文中代碼能夠轉變爲原型鏈

var yetAnotherPerson = object(person); => var yetAnotherPerson = Object.create(person);

5 寄生式繼承

核心:使用原型式繼承得到一個目標對象的淺複製,而後加強這個淺複製的能力。
優缺點:僅提供一種思路,沒什麼優勢

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"

6 寄生組合繼承

剛纔說到組合繼承有一個會兩次調用父類的構造函數形成浪費的缺點,寄生組合繼承就能夠解決這個問題。

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);

優缺點:這是一種完美的繼承方式。

7:ES6 Class extends

核心: ES6繼承的結果和寄生組合繼承類似,本質上,ES6繼承是一種語法糖。可是,寄生組合繼承是先建立子類實例this對象,而後再對其加強;而ES6先將父類實例對象的屬性和方法,加到this上面(因此必須先調用super方法),而後再用子類的構造函數修改this。

class A {} class B extends A { constructor() { super(); } }
class A { } class B { } Object.setPrototypeOf = function (obj, proto) { obj.__proto__ = proto; return obj; } // B 的實例繼承 A 的實例
Object.setPrototypeOf(B.prototype, A.prototype); // B 繼承 A 的靜態屬性
Object.setPrototypeOf(B, A);

ES6繼承與ES5繼承的異同:
相同點:本質上ES6繼承是ES5繼承的語法糖
不一樣點:

  • ES6繼承中子類的構造函數的原型鏈指向父類的構造函數,ES5中使用的是構造函數複製,沒有原型鏈指向。
  • ES6子類實例的構建,基於父類實例,ES5中不是。
相關文章
相關標籤/搜索