JS 繼承的正確操作

SuperSuperJoker發表於2020-10-26

首先,我們先要明白,JS裡的繼承,是對原型的繼承,而不是改變建構函式的原型

那這句話到底是什麼意思呢?讓我們通過一個例子解釋一下。

    function User() {}
    function Admin() {}
    User.prototype.name = function () {
        console.log("user name")
    };

    Admin.prototype = User.prototype;
    let admin = new Admin();
    admin.name(); //user name

這裡我們往User的原型物件中新增了一個name方法,而且我們的Admin函式也希望能呼叫到User原型物件下的name方法,因此這裡我們把User的原型物件直接賦值給了Admin的原型物件,也就是說Admin的原型物件被替換成了User的原型物件。

這種方法乍一看好像是沒有問題的,也能順利使用到User原型物件上的方法。但是當我們有多個函式同時希望通用到User原型物件上的方法的時候,問題就來了。

    function User() {}
    function Admin() {}
    function Member() {}
    Member.prototype = User.prototype;
    Admin.prototype = User.prototype;
    User.prototype.name = function () {
        console.log("user name")
    };
    Admin.prototype.role = function () {
        console.log("admin.role")
    };
    Member.prototype.role = function () {
        console.log("Member.role")
    };
    let a = new Admin();
    a.role(); 
    let m = new Member();
    m.role();

當我們的Member建構函式和Admin的建構函式的原型物件都改為User的原型物件的時候,Member和Admin本身原型物件上的方法自然而然就新增到了User的原型物件中了,而當Member的方法名跟Admin的方法名相同的時候,就會出現覆蓋的情況(後呼叫的方法覆蓋前一個方法),就會導致其中一個函式的方法不可使。

比如說在我們生活中,張三繼承了一筆財產,是在自己原有財產的基礎上新增了一筆財產,而不是繼承了財產之後原來的財產小時掉。

因此這種直接改變原型物件的方式不是繼承!

那正確的做法是什麼呢?

我們知道,我們的建構函式的原型物件的物件原型指向的都是Object,因此我們可以通過改變物件原型實現正確繼承的方法。

    function User() {}
    function Admin() {}
    function Member() {}
    Member.prototype.__proto__ = User.prototype;
    Admin.prototype.__proto__ = User.prototype;

    User.prototype.name = function () {
        console.log("user name")
    };
    Admin.prototype.role = function () {
        console.log("admin.role")
    };
    Member.prototype.role = function () {
        console.log("Member.role")
    };
    let a = new Admin();
    a.role();
    let m = new Member();
    m.role();

此時經過這樣設定之後,我們的Member和Admin的原型物件的物件原型指向的就不再是Object了,而是User的原型物件。通過這種做法,我們能讓Menber和Admin保留它們自身的方法,還能讓他們都共用到User原型物件中的方法。這就是真正意義上的繼承。

相關文章