原型鏈實現繼承的6種方式

San_Alex發表於2018-09-12

原型鏈

function parent(){
    this.name = 'asd'
}
function child(){
    
}
child.prototype = new parent()
const instance = new child()
alert(instance.name)    //'asd'
複製程式碼

因為此模式會共享屬性和方法,所以當一個例項修改屬性和方法時會影響其他例項,而且子型別無法向超型別傳遞引數。綜上,不推薦使用此模式。

借用建構函式

function parent(name){
    this.name = name
}

function child() {
    parent.call(this,'sda')
    this.age = 25
}

const instance = new child()
alert(instance.name) //'sda'
alert(isntance.age)  //25
複製程式碼

此模式解決了上一模式的存在的兩個問題,但還是存在一個小問題,所以還是不推薦使用。下面是此模式的優缺點。

  1. 每一個child的例項都有name屬性的副本,避免了屬性修改的傳染性。
  2. 子型別可以向超型別傳遞引數
  3. 函式無法複用

組合繼承

function parent(name) {
    this.name = name
    this.colors = ['red']
}

parent.prototype.sayName = () => {
    alert(this.name)
}

function child(name, age) {
    parent.call(this, name)
    this.age = age
} 

child.prototype = new parent()
child.prototype.constructor = child
child.prototype.sayAge = () => {
    alert(this.age)
}

複製程式碼

此模式完美的解決了前面兩種模式存在的問題,適用於絕大多數的場景,因此推薦使用該模式。

原型式繼承

const person = {
    name: 'sa',
    friends: ['ad', 'da']
}
function object(original) {
    function F() {}
    F.prototype = original
    return new F()
}
//Object.create()是object()的規範實現
const anotherPerson = Object.create(person)
複製程式碼

該模式在一個物件的基礎上建立一個類似的物件,優點是可以節省書寫建構函式的程式碼。由於還是同原型式一樣共享屬性和方法,所以也具有原型式的問題。

寄生式繼承

var person = {
    name: 'sa',
    friends: ['ad', 'da']
}

function createAnother(original) {
    const clone = Object.create(original)
    clone.say = () => {
        alert('hello')
    }
}
var anotherPerson = createAnother(person)
anotherPerson.say();  //hello
複製程式碼

該模式類似於原型式繼承,不過這模式在內部實現了增強物件,而且此模式使用於任何返回新物件的函式,所以推薦使用。

寄生組合式繼承

function inheritPrototype(child, parent) {
    const portotype = Object.create(parent)
    prototype.constructor = child 
    child.prototype = prototype
}
複製程式碼

由於該模式只呼叫了一次parent建構函式,因此避免了組合式呼叫兩次parent建構函式所建立的不必要的、多餘的屬性。該模式可謂是結合了寄生式繼承和組合式繼承兩種模式的優點,是上述模式的集大成者,所以該模式被廣泛認為是引用型別最理想的繼承正規化。

相關文章