javascript繼承分析
阿新 • • 發佈:2017-09-26
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繼承分析