關(guān)于繼承,其實(shí)寫(xiě)js將近一年,平時(shí)其實(shí)是幾乎不怎么使用繼承的键闺,但是最近面試的時(shí)候遇到了繼承的問(wèn)題,所以查找了一些資料之后做一個(gè)總結(jié)澈驼。主要總結(jié)的點(diǎn)有:
- 原型鏈繼承
- 組合繼承
- 寄生組合繼承
原型鏈繼承
假設(shè)父類(lèi)Person辛燥,子類(lèi)Ninja。原型鏈繼承的方式如下:
function Person(){
this.info = {
name:'xiaobo',
age:23
};
}
Person.prototype.sayName = function(){
console.log(this.info.name);
}
Person.prototype.sayAge = function(){
console.log(this.info.age);
}
function Ninja(age){
this.info.age = age || 23;
}
//子類(lèi)的原型直接等于父類(lèi)的一個(gè)實(shí)例
Ninja.prototype = new Person();
var ninja1 = new Ninja(20);
var ninja2 = new Ninja(24);
ninja1.sayAge();//24
ninja2.sayAge();//24
這種方式的根本原理其實(shí)就是子類(lèi)構(gòu)造函數(shù)的原型等于父類(lèi)的一個(gè)實(shí)例缝其,這樣很簡(jiǎn)單挎塌,但是也會(huì)帶來(lái)一個(gè)問(wèn)題:父類(lèi)的非原型屬性或者非原型方法會(huì)被所有子類(lèi)的實(shí)例共享,從而導(dǎo)致引用類(lèi)型的變量會(huì)被所有的子類(lèi)實(shí)例共享内边,這個(gè)特性并不是繼承的初衷榴都。為了解決這個(gè)問(wèn)題,所以有了組合繼承漠其。
組合繼承
原型繼承導(dǎo)致父類(lèi)的非原型屬性被所有實(shí)例共享從而導(dǎo)致的引用屬性一個(gè)修改引起所有子類(lèi)實(shí)例修改的情況嘴高,組合繼承可以很好的解決這個(gè)問(wèn)題。
function Person(){
this.info = {
name:'xiaobo',
age:23
};
}
Person.prototype.sayName = function(){
console.log(this.info.name);
}
Person.prototype.sayAge = function(){
console.log(this.info.age);
}
function Ninja(age){
//在構(gòu)造函數(shù)中調(diào)用父類(lèi)構(gòu)造方法從而給每個(gè)子類(lèi)實(shí)例添加一個(gè)屬性和屎,從而子類(lèi)實(shí)例之間不會(huì)相互影響
Person.call(this);
this.info.age = age || 23;
}
Ninja.prototype = new Person();
var ninja1 = new Ninja(20);
var ninja2 = new Ninja(24);
var ninja3 = new Ninja();
ninja1.sayAge(); //20
ninja2.sayAge(); // 24
ninja3.sayAge(); //23
console.log(ninja1.__proto__.info.age); //23
console.log(ninja2.__proto__.info.age); //23
console.log(ninja3.__proto__.info.age); //23
但是組合繼承又引入了一個(gè)問(wèn)題拴驮,兩次調(diào)用父類(lèi)的構(gòu)造函數(shù),會(huì)造成一些冗余柴信,在每個(gè)子類(lèi)實(shí)例的原型上套啤,其實(shí)也是存儲(chǔ)了一個(gè)指向父類(lèi)非原型屬性的一個(gè)引用,數(shù)據(jù)有冗余颠印,而寄生組合可以很好的解決這個(gè)問(wèn)題纲岭。
寄生組合繼承
function Person(){
this.info = {
name:'xiaobo',
age:23
};
}
Person.prototype.sayName = function(){
console.log(this.info.name);
}
Person.prototype.sayAge = function(){
console.log(this.info.age);
}
function Ninja(age){
//調(diào)用父類(lèi)構(gòu)造函數(shù)
Person.call(this);
this.info.age = age || 23;
}
//寄生繼承
Ninja.prototype = Object.create(Person.prototype);
Ninja.prototype.constructor = Ninja;
//此處添加Ninja的新方法
// -----
var ninja1 = new Ninja(20);
var ninja2 = new Ninja(24);
var ninja3 = new Ninja();
ninja1.sayAge();//20
ninja2.sayAge();//24
ninja3.sayAge();//23
console.log(ninja1.__proto__.info);//undefined
console.log(ninja2.__proto__.info);//undefined
console.log(ninja3.__proto__.info);//undefined
console.dir(Ninja.prototype);
這種繼承方式抹竹,是公認(rèn)的最理想的繼承方式,能夠很好的彌補(bǔ)之前的不足止潮。在這里再簡(jiǎn)單介紹一下Object.create,內(nèi)部發(fā)生的情況大概是這樣:
Object.Prototype.create = Object.prototype.create || function(obj){
function F(){};
F.prototype = obj;
return new F();
}
小結(jié)
個(gè)人認(rèn)為窃判,上述三種繼承方式,原型鏈方式最為簡(jiǎn)單喇闸,但是存在問(wèn)題袄琳,而組合繼承方式彌補(bǔ)了不足,但是又帶來(lái)了數(shù)據(jù)的冗余燃乍,寄生組合式能很好的解決所有的問(wèn)題唆樊,是公認(rèn)的最佳繼承方式。
參考資料
- js高程程序設(shè)計(jì)