1. 程式人生 > >javascript繼承分析

javascript繼承分析

arguments nbsp 實例化 cal type 我們 實例 很大的 pro

一,傳統JS繼承方法:

  1,原型式繼承:

    

//聲明父類
function Person(name,age){   
    this.name = name;
    this.age = age;
    this.flag = true;
}
// 給父類添加方法
Person.prototype.sayName = function(){
    console.log(this.name);
}

//實例化父類
var person = new Person(zhl,30);
//調用父類方法
person.sayName();  // zhl

// 聲明子類
function Worker(name,age,work){
    
this.name = name; this.age = age; this.work = work; } //原型式繼承 其實就是子類的原型指向父類的一個實例 Worker.prototype = new Person(); //給子類添加方法 Worker.prototype.sayWork = function(){ console.log(this.work); } //實例化一個子類 var worker = new Worker(vsmart,32,itcoder); //調用子類方法 worker.sayName(); // vsmart worker.sayWork(); //
itcoder

  貌似可以用了,不要高興太早,這裏是有很大的坑的!

  此繼承方法有幾個弊端:

  1,聲明父類與子類的構造函數中有很多重復的初始化賦值;

  2,實例化子類的對象 flag 屬性竟然是 true

    然而這個屬性本身子類並沒有初始化,哪來的?

    console.log(worker.flag) //true
    console.log(Worker.prototype.flag) //true

    哦,原來是從子類的原型上查找到的,也就是從父類的一個實例上獲取到的;

    本來我們要做到 屬性與方法分離的,現在呢,這個屬性竟然在原型上,原型應該只放方法才對。

  3,子類的構造函數 constructor 竟然指向了 父類的 constructor,這個指向錯誤將來勢必會帶來耦合

    console.log(worker.constructor) //

function Person(name,age){
    this.name = name;
    this.age = age;
    this.flag = true;
}

  綜合以上幾點我們要做優化;

  1,我們可以借用父類的構造函數初始化子類的構造函數 利用 apply 或 call 改變指向

  2,我們要重新改變子類的構造函數指向

  

//聲明父類
function Person(name,age){   
    this.name = name;
    this.age = age;
    this.flag = true;
}
// 給父類添加方法
Person.prototype.sayName = function(){
    console.log(this.name);
}

//實例化父類
var person = new Person(‘zhl‘,30);
//調用父類方法
person.sayName();  // zhl

// 聲明子類
function Worker(name,age,work){
    Person.apply(this,arguments);  // 借用父類構造方法
    this.work = work;
    this.flag = false;
}
//原型式繼承  其實就是子類的原型指向父類的一個實例
Worker.prototype = new Person();
//給子類添加方法
Worker.prototype.sayWork = function(){
    console.log(this.work);
}
//改變constructor指向
Worker.prototype.constructor = Worker;

//實例化一個子類
var worker = new Worker(‘vsmart‘,32,‘itcoder‘);
//調用子類方法
worker.sayName();  // vsmart
worker.sayWork(); // itcoder

console.log(worker.flag) //false    //子類自己的屬性
console.log(Worker.prototype.flag)  //true  從子類原型上查找
console.log(worker.constructor) //正確指向自己的構造方法

  function Worker(name,age,work){
    Person.apply(this,arguments);
    this.work = work;
    this.flag = false;
  }



  2,混合拷貝繼承:

     所謂混合拷貝繼承是指,構造函數還是借用父類的方式,但方法繼承就是模擬拷貝的方式,

    

//聲明父類
function Person(name,age){   
    this.name = name;
    this.age = age;
    this.flag = true;
}
// 給父類添加方法
Person.prototype.sayName = function(){
    console.log(this.name);
}

//實例化父類
var person = new Person(‘zhl‘,30);
//調用父類方法
//person.sayName();  // zhl

// 聲明子類
function Worker(name,age,work){
    Person.apply(this,arguments);
    this.work = work;
    this.flag = false;
}
//原型式繼承  其實就是子類的原型指向父類的一個實例
extends2(Worker.prototype,Person.prototype);
//給子類添加方法
Worker.prototype.sayWork = function(){
    console.log(this.work);
}
//拷貝繼承核心方法
function extends2(child,parent){
    for(var attr in parent){
        if(parent.hasOwnProperty(attr)){
            child[attr] = parent[attr];
        }
    }
}

//實例化一個子類
var worker = new Worker(‘vsmart‘,32,‘itcoder‘);
//調用子類方法
worker.sayName();  // vsmart
worker.sayWork(); // itcoder

console.log(worker.flag) //false    //子類自己的屬性
console.log(Worker.prototype.flag)  //false  子類原型上沒有查找到
console.log(worker.constructor)   //
/*function Worker(name,age,work){
    Person.apply(this,arguments);
    this.work = work;
    this.flag = false;
}*/

  

    

javascript繼承分析