js各類繼承方式和優缺點介紹

1.原型鏈繼承

function Parent () {
        this.name = 'kevin';
    }
    
    Parent.prototype.getName = function () {
        console.log(this.name);
    }
    
    function Child () {
        
    }
    Child.prototype = new Parent();
    
    var child1 = new Child();
    
    console.log(child1.getName()) // kevin
複製代碼

缺點bash

  • 1.引用類型的屬性被全部實例共享 👇
function Parent () {
        this.names = ['kevin', 'daisy'];
    }
    function Child () {
        
    }
    
    Child.prototype = new Parent();
    
    var child1 = new Child();
    
    child1.names.push('yayu');
    
    console.log(child1.names); // ["kevin", "daisy", "yayu"]
    
    var child2 = new Child();
    
    console.log(child2.names); // ["kevin", "daisy", "yayu"]
複製代碼
  • 2.在建立Child的實例時,不能向Parent傳參

2.借用構造函數(經典繼承)

function Parent () {
        this.names = ['kevin', 'daisy'];
    }
    
    function Child () {
        Parent.call(this);
    }
    
    var child1 = new Child();
    
    child1.names.push('yayu');
    
    console.log(child1.names); // ["kevin", "daisy", "yayu"]
    
    var child2 = new Child();
    
    console.log(child2.names); // ["kevin", "daisy"]
複製代碼

優勢函數

  • 一、避免了引用類型的屬性被全部實例共享
  • 二、能夠在Child中向Parent傳參 👇
function Parent (name) {
        this.name = name;
    }
    
    function Child (name) {
        Parent.call(this, name);
    }
    
    var child1 = new Child('kevin');
    
    console.log(child1.name); //kevin
    
    var child2 = new Child('daisy');
    
    console.log(child2.name); // daisy
複製代碼

缺點ui

  • 方法都在構造函數中定義,每次建立實例都會建立一遍方法

3.組合繼承(原型鏈繼承和經典繼承雙劍合璧)

function Parent (name) {
        this.name = name;
        this.colors = ['red', 'blue', 'green'];
    }
    
    Parent.prototype.getName = function () {
        console.log(this.name)
    }
    
    function Child (name, age) {
        Parent.call(this, name);
        this.age = age;
    }
    
    Child.prototype = new Parent();
    
    var child1 = new Child('kevin', '18');
    
    child1.colors.push('black');
    
    console.log(child1.name); // kevin
    console.log(child1.age); // 18
    console.log(child1.colors); // ["red", "blue", "green", "black"]
    
    var child2 = new Child('daisy', '20');
    
    console.log(child2.name); // daisy
    console.log(child2.age); // 20
    console.log(child2.colors); // ["red", "blue", "green"]
複製代碼

優勢this

  • 融合原型鏈繼承和構造函數的優勢,是JavaScript中最經常使用的繼承模式。

4.原型式繼承

function createObj (o) {
        function F () {}
        F.prototype = o;
        return new F();
    }
複製代碼

就是ES5 Object.create的模擬實現,將傳入的對象做爲做爲建立的對象的原型。spa

缺點prototype

包含引用類型的屬性值始終都會共享相應的值,這點跟原型鏈繼承同樣。code

var person = {
        name: 'kevin',
        friends: ['daisy', 'kelly']
    }
    
    var person1 = createObj(person);
    var person2 = createObj(person);
    
    person1.name = 'person1';
    console.log(person2.name); // kevin
    
    person1.friends.push('taylor');
    console.log(person2.friends); // ["daisy", "kelly", "taylor"]
複製代碼

注意: 修改person1.name的值,person2.name的值並未發生改變,並非由於person1和person2有獨立的name值,而是由於person1.name = 'person1',給person1添加了name值,並未修改了原型上的name值。對象

5.寄生式繼承

建立一個僅用於封裝繼承過程的函數,該函數在內部以某種形式來作加強對象,最後返回對象繼承

function createObj (o) {
        var clone = object.create(o);
        clone.sayName = function () {
            console.log('hi');
        }
        return clone;
    }
複製代碼

缺點 跟借用構造函數模式同樣,每次建立對象都會建立一遍方法。seo

6.寄生組合式繼承

爲了方便你們閱讀,在這裏重複一下組合繼承的代碼:

function Parent (name) {
        this.name = name;
        this.colors = ["red", "blue", "green"];
    }
    
    Parent.prototype.getName = function () {
        console.log(this.name)
    }
    
    function Child (name, age) {
        Parent.call(this, name);
        this.age = age;
    }
    
    Child.prototype = new Parent();
    
    var child1 = new Child('kevin', '18');
    
    console.log(child1)
複製代碼

組合繼承最大的缺點是會調用兩次父構造函數。

一次是設置子類型實例的原型的時候:

Child.prototype = new Parent();
複製代碼

一次在建立子類型實例的時候:

var child1 = new Child('kevin', '18');
複製代碼

回想下new的模擬實現,其實在這句中,咱們會執行:

Parent.call(this, name);
複製代碼

在這裏,咱們又會調用了一次Parent構造函數。

因此,在這個例子中,若是咱們打印child1對象,咱們會發現Child.prototype和child1都有一個屬性爲color,屬性值爲["red", "blue", "green"]。

那麼咱們該如何避免這一次重複調用呢?

若是咱們不使用Child.prototype = new Parent(),而是直接的讓Child.prototype訪問到Parent.prototype呢? 👇

function Parent (name) {
        this.name = name;
        this.colors = ['red', 'blue', 'green'];
    }
    
    Parent.prototype.getName = function () {
        console.log(this.name)
    }
    
    function Child (name, age) {
        Parent.call(this, name);
        this.age = age;
    }
    
    //關鍵的第3步
    var F = function () {};
    
    F.prototype = Parent.prototype;
    
    Child.prototype = new F();
    
    
    var child1 = new Child('kevin', '18');
    
    console.log(child1);
複製代碼

最後咱們封裝一下這個繼承方法:

function object (o) {
        function F () {}
        F.prototype = o;
        return new F();
    }
    
    function prototype(child, parent) {
        var prototype = object(parent.prototype);
        prototype.constructor = child;
        child.prototype = prototype;
    }
    
    //使用
    prototype(Child, Parent);
複製代碼

優勢

  • 這種方式的高效率體現它只調用了一次Parent構造函數,而且所以避免了在Parent.prototype上面建立沒必要要的、多餘的屬性。與此同時,原型鏈還保持不變;所以,還可以正常使用instanseof和isPrototypeOf。開發人員廣泛認爲寄生組合式繼承是引用類型最理想的繼承方式。
相關文章
相關標籤/搜索