js繼承的方式總結

js繼承的方式總結

  1. 對象冒充
  2. call()函數
  3. apply()函數
  4. 原型鏈
  5. 混合方式

對象冒充

        function Father(name,age,sex){
            this.name=name;
            this.age=age;
            this.sex=sex;
            this.say=function(){
                alert('hello world');
            }
        }
        function Son(name,age,sex){
            this.extend=Father;//將構造方法當成普通方法使用,賦值給屬性
            this.extend(name,age,sex);//調用
            delete this.extend;//刪除對Father的引用
            //所有新屬性和新方法都必須在刪除了新方法的代碼行後定義。否則,可能會覆蓋超類的相關屬性和方法,因爲this.extend創建了對Father的引用        
        }
        var son=new Son('son',18,'男');
        var father=new Father('father',38,'男');
        console.log(son.name);//son
        console.log(father.name);//father

實現原理:讓父類的構造函數成爲子類的方法,然後調用該子類的方法,通過this關鍵字給所有的屬性和方法賦值。
該種實現方式可以實現多繼承。
這裏存在一個弊端,如果存在兩個類 ClassA 和 ClassB 具有同名的屬性或方法,ClassB 具有高優先級。因爲它從後面的類繼承。除這點小問題之外,用對象冒充實現多重繼承機制輕而易舉。

call()函數

        function Father(name,age,sex){
            this.name=name;
            this.age=age;
            this.sex=sex;
            this.say=function(){
                alert('hello world');
            }
        }
        function Son(name,age,sex,grade){
            Father.call(this,name,age,sex);
            this.grade=grade;
        }
        var son=new Son('key',18,'男',100);
        console.log(son.name);//key
        console.log(son.grade);//100

實現原理:改變函數內部的函數上下文this,使它指向傳入函數的具體對象。
該種方式不能繼承原型鏈,若想繼承原型鏈,則採用第5種混合模式。

apply()函數

        function Father(name,age,sex){
            this.name=name;
            this.age=age;
            this.sex=sex;
            this.say=function(){
                alert('hello world');
            }
        }
        function Son(name,age,sex,grade){
            Father.apply(this,[name,age,sex]);//參數以數組的形式
            this.grade=grade;
        }
        var son=new Son('key',18,'男',100);
        console.log(son.name);//key
        console.log(son.grade);//100

實現原理:改變函數內部的函數上下文this,使它指向傳入函數的具體對象。
該種方式不能繼承原型鏈,若想繼承原型鏈,則採用5混合模式,與call()函數的區別就是參數是以數組的形式傳人。

原型鏈

        function Father(name,age,sex){
            this.name=name;
            this.age=age;
            this.sex=sex;
            this.say=function(){
                alert(this.name);
            }
        }
        function Son(grade){
            this.grade=grade;
        }
        /*調用 Father 的構造函數,沒有給它傳遞參數。這在原型鏈中是標準做法。要確保構造函數沒有任何參數。
        與對象冒充相似,子類的所有屬性和方法都必須出現在 prototype 屬性被賦值後,因爲在它之前賦值的所有方法都會被刪除。爲什麼?因爲 prototype 屬性被替換成了新對象,添加了新方法的原始對象將被銷燬。*/
        Son.prototype=new Father();//直接將實例賦值給子類原型
        var son=new Son(100);
        son.name="key";
        console.log(son.name);//key
        son.say();//key

實現原理:使子類原型對象指向父類的實例以實現繼承,即重寫類的原型,弊端是不能直接實現多繼承。

混合方式

        function Father(name) {
            this.name = name;
        }
        Father.prototype.say = function () {
            alert(this.name);
        };
        function Son(name, age) {
            Father.call(this, name);
            this.age = age;
        }
        Son.prototype = new Father();
        Son.prototype.sayAge = function () {
            alert(this.age);
        };
        var father = new Father("father");
        var son = new Son("son", 18);
        father.say();//father
        son.say();//son
        son.sayAge();//18

以下是w3cSchool中的原話,我覺得寫的很好!
對象冒充的主要問題是必須使用構造函數方式,這不是最好的選擇。不過如果使用原型鏈,就無法使用帶參數的構造函數了。開發者如何選擇呢?答案很簡單,兩者都用。
我們曾經講解過創建類的最好方式是用構造函數定義屬性,用原型定義方法。這種方式同樣適用於繼承機制,用對象冒充繼承構造函數的屬性,用原型鏈繼承 prototype 對象的方法。

目錄

瀏覽器兼容

  1. 所有主流瀏覽器都兼容。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章