繼承是JS中非常內(nèi)容九孩,原因就是JS沒有地道的繼承方式哪替,我們只能通過各種方式來模擬面向?qū)ο笾械睦^承柱彻。下面介紹幾種常見的繼承方式及其不足拄查。
構(gòu)造函數(shù)繼承
function Parent1 (){
this.name = 'parent'
}
function Child1() {
Parent1.call(this);
this.type = 'child1';
}
缺點(diǎn):Parent1 原型鏈上的東西并不會繼承吁津,這種方式,所以只實(shí)現(xiàn)了部分繼承堕扶,如果父類的屬性都在構(gòu)造函數(shù)中碍脏,沒問題,但是如果有一部分在原型鏈上稍算,那么就繼承不了典尾,為了解決這個不足我們就要使用原型鏈來進(jìn)行原型繼承。
原型繼承
function Parent2() {
this.name = 'Parent2';
this.res = [1, 2, 3]
}
function Child2 () {
this.type = 'Child2'
}
Child2.prototype = new Parent2()
var child2 = new Child2();
var child3 = new Child3();
child2.res.push(4);
console.log(child3.res) // 1,2,3,4
缺點(diǎn) : 這種方式缺點(diǎn)也很明顯糊探,實(shí)例的兩個對象钾埂,如果一個對象改變res的值,那么另一個對象 的res屬性也會被改變(這兩個對象共享一個原型)科平,這違背了獨(dú)立性岛心。
組合
function Parent3() {
this.name = 'parent3';
this.res = [1, 2, 3];
}
function Child3() {
Parent3.call(this);
this.type = 'child3';
}
Child3.prototype = Parent3.prototype;
var child = new Child3();
缺點(diǎn):此時child.constructor
并不是Child3
磨隘;而是Parent3
,這是因?yàn)楫?dāng)我們想獲取child.constructor
實(shí)際上是訪問Child3.prototype.constructor
(也就是說constructor這個屬性是存在于原型上誉结,并不是直接在child這個對象上)驶沼,而Child3.prototype
此時等于Parent3.prototype
,所以最后constructor
的屬性值為Parent3
襟己。
組合優(yōu)化
function Parent4() {
this.name = 'parent4';
this.res = [1, 2, 3];
}
function Child4() {
Parent4.call(this);
this.type = 'child4';
}
Child4.prototype = Object.create(Parent4.prototype);
// Child4.prototype = Parent4.prototype;
Child4.prototype.constructor = Child4;
在這里我們加上這句Child4.prototype = Object.create(Parent4.prototype);
的目的是為了隔離子類原型和父類原型犬第,現(xiàn)在就是Child4.prototype.__proto__ === Parent4.prototype
诀姚,如果我們不加,直接修正子類的構(gòu)造函數(shù)(Child4.prototype.constructor = Child4;
)那么也會把父類的Parent4.prototype.constructor
更改成Child4
妓湘,因?yàn)榇藭rChild4.prototype
和Parent4.prototype
指向同一地址查蓉。
注: 如果這里不支持Object.create,我們可以采用下面的plolly
function F(){} F.prototype = Parent4.prototype Child4.prototype = new F()
缺點(diǎn):貌似還沒有實(shí)現(xiàn)靜態(tài)屬性的繼承
實(shí)現(xiàn)靜態(tài)屬性的繼承
function Parent() {
this.age = 20
}
Parent.sex = 'male';
Parent.habby = 'badminton';
function Child() {
Parent.call(this);
this.type = 'Child';
if (Object.setPrototypeOf) {
Object.setPrototypeOf(Child, Parent)
} else if (Child.__proto__) {
Child.__proto__ = Parent
} else {
for (var attr in Parent) {
if (Parent.hasOwnProperty(attr) && !(attr in Child)) {
Child[attr] = Parent[attr]
}
}
}
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
var child = new Child();
var parent = new Parent();
console.log(child)
for (var key in Child) {
console.log(key)
}
console.log(child.constructor)
console.log(parent.constructor)
console.log(child instanceof Child)
console.log(child instanceof Parent)
看似完美了,但是還有一個問題多柑,就是如果后續(xù)父類繼續(xù)添加一些靜態(tài)的方法奶是,是不會自動同步到子的靜態(tài)方法上面去的。