1. 程式人生 > >javascript高階程式設計之---繼承

javascript高階程式設計之---繼承

物件的繼承

 1.繼承的思想:關鍵是將一個建構函式A的原型指向給另一個建構函式B的例項本身,那麼A例項將擁有(繼承)B例項的所有的屬性和方法(繼承在原型)

  2.原理:將一個建構函式A的原型指向給另一個建構函式B的例項本身,也就意味著A原型將繼承B例項本身擁有的所有的屬性和方法;而對於A例項而言,A原型物件中的所有的屬性和方法是A例項所共享的,也就是說A例項所共享的例項和方法就是B例項本身所擁有的一切屬性和方法,這就好像A例項繼承了B例項的屬性和方法一樣。

3.繼承的一些常用的實現方法:

3.1.組合繼承(最常用的繼承方法)

  這裡所謂的”組合“就是原型鏈和建構函式的技術整合到一起,分別發揮各自的優勢:具體思想是:通過原型鏈繼承原型上的屬性和方法,通過借用建構函式實現對例項屬性的繼承。(想方設法將被繼承者的例項屬性”寫“到繼承者的例項屬性值中去,這就用到了call(apply))


function SuperType(name) {
            this.name = name;
            this.colors = ["red", "blue", "green"];
        }
        SuperType.prototype.sayName = function () {
            console.log(this.name);
        }
        function SubType(name, age) {
            //繼承屬性(例項屬性)
            // 在當前環境中執行了函式SuperType(name),
            //相當於再這裡寫了一下程式碼:this.name = name;this.colors = ["red","blue","green"];
            SuperType.call(this, name);
            this.age = age;//自己定義一個例項屬性age
        }
        //通過願原型鏈繼承方法
        SubType.prototype = new SuperType();//要記得該例項本身是一個物件,其繼承的原型中的方法sayName在該物件的__proto__屬性中,因為例項.__proto__指向原型
        SubType.prototype.constructor = SubType;
        //這句話的作用是將SubType例項的constructor指向其本身(這樣才正常),如果不寫的話將會指向SuperType
        //因為SubType.prototype.constructor = new SuperType().constructor = SuperType
        SubType.prototype.sayAge = function () {
            console.log(this.age);
        };
        var instance1 = new SubType("Nicholas", 29);
        instance1.colors.push("black");//此時的color是一個例項屬性,而不是一個原型中的屬性
        console.log(instance1.colors); //"red,blue,green,black"
        instance1.sayName(); //"Nicholas";,通過原型鏈繼承於SuperType原型中的方法
        instance1.sayAge(); //29

        var instance2 = new SubType("Greg", 27);
        console.log(instance2.colors); //"red,blue,green"
        instance2.sayName(); //"Greg";
        instance2.sayAge(); //27

3.2.原型式繼承

使用Object.create(ele1,[ele2])方法;ele1:是作為新物件原型的物件,ele2是為新物件定義新屬性或方法的物件(可有可無),由於ele2是為新物件直接定義的屬性和方法,所以會覆蓋與原型ele1中同名的屬性和方法,ele2的寫法和 Object.defineProperties()中的第二個引數一樣

var obj = {
            name:"張三",
            teammates:["李四","王五","李六"]
        }
        var objInstance = Object.create(obj);
        console.log(objInstance)
        // 這裡obj就是作為新物件objInstance原型的物件,也就是說objInstance.__proto__指向obj
        console.log(objInstance.__proto__);//obj,新建立的物件將擁有該原型的所有的屬性和方法,因為obj是作為該物件的原型,
                                            //那麼原型中的所有的屬性和方法都將被例項物件所共享;
        console.log(objInstance.name)//張三,訪問的是原型obj中的屬性,因為原型中的屬性和方法被共享,所以例項能夠訪問對應的屬性和方法;
        console.log(objInstance.teammates)//["李四","王五","李六"],理由同上



        objInstance.name = "李四";//相當於對該例項物件添加了一個例項數屬性name,原型中的name屬性並沒有改變,因為 objInstance.name儲存的是一個基本型別的值;
        objInstance.teammates.push("張千子")//原型中的對應屬性將會被改變,因為objInstance.teammates儲存的是一個指標,指向原型中的teammates,所以相當於給原型中的teammates
                                           //屬性執行了push方法
        objInstance.teammates = ["李白","杜甫"];//原指標斷了,現在objInstance.teammates指標指向新的陣列,相當於給物件objInstance設定了一個新的例項屬性teammates,
                                            //但是原型中的teammates屬性並沒有發生改變,
        console.log(objInstance)//有兩個例項屬性和原型
        console.log(obj)//teammates屬性已經發生了改變,變成了["李四","王五","李六","張千子"];





        var objInstance1 = Object.create(obj,{
            name:{
                value:"呵呵噠"
            },
            sex:{
                value:"未知"
            }
        })
        console.log(objInstance1)//不用多解釋了吧

3.3.寄生式繼承

說白了就是封裝一個函式,該函式通過接收一個來作為新物件基礎物件的引數來建立一個新物件,然後在函式體內”增強“新物件(為新物件新增新的屬性和方法),最後返回新物件即可。

//該函式的目標是建立一個新的空物件,該空物件將繼承param的方法和屬性
        function object(param){
            function F(){};//建構函式
            F.prototype = param;//建構函式F的原型指向了param物件,也就意味著F的例項也將擁有param物件所擁有的屬性和方法(共享於原型中的屬性和方法)
           console.log(new F().constructor)//Object建構函式
            return new F()//空物件,該空物件例項將通過原型繼承param裡面的屬性和方法
        }

        function createObj(baseObj){
            var newObj = object(baseObj);//產生了一個新的物件
            newObj.height = 170;//為該物件新增新的屬性和方法,新的屬性或者方法將是例項屬性和方法
            return newObj//return 出新的物件
        }
        var base = {
            name:"張三",
            age:25
        }
        console.log(createObj(base))

3.4.寄生組合式繼承

即通過借用建構函式來繼承屬性,通過原型鏈的混成形式來繼承方法。

其背後的基本思路是:不必為了指定子型別的原型而呼叫超型別的建構函式,我們所需要的無非就是超型別原型的一個副本而已。本質上,就是使用寄生式繼承來繼承超型別的原型,然後再將結果指定給子型別的原型。

//函式封裝
        function inheritPrototype(subType, superType) {
            var prototype = object(superType.prototype); //一個空物件,該物件的原型指向了superType.prototype
            prototype.constructor = subType; //給上面的空物件的原型重新指定constroctor屬性(為什麼說constructor屬性指向的空物件是原型中的呢,那是因為空物件中的例項屬性沒有該屬性,但是原型中有)
            subType.prototype = prototype; //將 subType.prototype指向prototype,那麼此時subType的原型將繼承了superType原型中的屬性和方法,因為constructor屬性進行了重定向,所以,此時
                                           //subType的原型此時真正的正規了
        }
        /*
            該函式的作用是的得到一個空物件但是該物件卻有公用屬性和方法
         */
        function SuperType(name) {
            this.name = name;
            this.colors = ["red", "blue", "green"];
        }
        SuperType.prototype.sayName = function () {//Supertype例項所共有的新的屬性和方法
            alert(this.name);
        };
        function SubType(name, age) {
            SuperType.call(this, name);
            this.age = age;
        }
        inheritPrototype(SubType, SuperType);
        //到這裡為止,SubType的例項屬性包括,name,colors,age;SubType的原型所包括的屬性和方法有
        //sayName方法,和一個指向SubType原型的constructor屬性....剩下的不解釋啦
        SubType.prototype.sayAge = function () {
            alert(this.age);
        };