來自紅寶書的幾種繼承方式
1. 原型鏈繼承
function SuperClass(){
this.text = ['hello', 'world'];
}
SuperClass.prototype.sayHi = function(){
console.log(this.text);
}
function SubClass(){
}
SubClass.prototype = new SuperClass();
var test1 = new SubClass();
test1.sayHi();// ["hello", "world"]
var test2 = new SubClass();
test2.text.push('shit');
test1.sayHi(); //["hello", "world", "shit"] 所有實(shí)例引用的都是同一個(gè)值
缺點(diǎn):
- 原型的屬性被所有實(shí)例共享
- 創(chuàng)建子類時(shí)不能向父類傳參
2. 借用構(gòu)造函數(shù)繼承
function SuperClass(data){
this.text = ['hello', 'world'];
this.data = data;
this.sayHi = function(){
console.log(this.text);
}
}
SuperClass.prototype.sayBye = function(){
console.log(bye);
}
function SubClass(data, name){
SuperClass.call(this, data);
this.name = name;
}
var test1 = new SubClass();
test1.sayHi(); //["hello", "world"]
var test2 = new SubClass();
test2.text.push('shit');
test1.sayHi(); //["hello", "world"]
test1.sayBye();//Uncaught TypeError: test1.sayBye is not a function
優(yōu)點(diǎn):
- 避免所有實(shí)例共享原型的屬性
- 可以向父類傳參
缺點(diǎn): - 只能繼承父類的實(shí)例屬性袍暴、方法辜荠,不能繼承原型上的屬性瘪松、方法
- 方法要在父類構(gòu)造函數(shù)中定義贪绘,每次創(chuàng)建子類實(shí)例都會(huì)創(chuàng)建一個(gè)方法的副本缩赛。子類實(shí)例間的方法相同卻不能復(fù)用昧狮。
3. 組合繼承
將原型鏈繼承和借用構(gòu)造函數(shù)繼承組合起來使用
function SuperClass(name) {
this.text = ['hello', 'world'];
this.name= name;
this.sayHi = function () {
console.log(this.name);
}
}
SuperClass.prototype.sayBye = function () {
console.log('bye');
}
function SubClass(name) {
SuperClass.call(this, name);
}
SubClass.prototype = new SuperClass();
SubClass.prototype.constructor = SubClass;
var test1 = new SubClass('one');
var test2 = new SubClass('two');
test1.sayHi(); //one
test2.sayHi(); //two
test2.sayBye(); //bye
缺點(diǎn):
調(diào)用了兩次父類構(gòu)造函數(shù)酿联,實(shí)例和原型有一樣的屬性的方法。
一個(gè)來自于SuperClass.call(this, data);
一個(gè)來自于SubClass.prototype = new SuperClass()
image.png
4. 原型式繼承
利用一個(gè)空函數(shù)作為中介扮饶,進(jìn)行原型的連接淮韭。
//這個(gè)操作其實(shí)就是ES5里面的Object.create
function inherits(obj) {
function F() { }
F.prototype = obj;
return new F();
}
function SuperClass(name) {
this.text = ['hello', 'world'];
this.name = name;
this.sayHi = function () {
console.log(this.name);
}
}
SuperClass.prototype.sayBye = function () {
console.log('bye');
}
var parent = new SuperClass('test');
var child1 = inherits(parent);
var child2 = inherits(parent);
child1.sayHi(); //test
child1.sayBye(); //bye
child1.text.push('shit');
console.log(child2.text); //["hello", "world", "shit"] 實(shí)例共享父類屬性
缺點(diǎn):與原型鏈繼承相同
5. 寄生式繼承
和原型式繼承一個(gè)意思
function createObj (o) {
var clone = Object.create(o);
clone.sayName = function () {
console.log('hi');
}
return clone;
}
缺點(diǎn):與原型式繼承相同
6. 寄生組合繼承
利用空函數(shù)來連接原型,代替組合繼承中的SubClass.prototype = new SuperClass()贴届,減少了一次父類構(gòu)造調(diào)用
function SuperClass(name) {
this.text = ['hello', 'world'];
this.name = name;
this.sayHi = function () {
console.log(this.name);
}
}
SuperClass.prototype.sayBye = function () {
console.log('bye');
}
function SubClass(name) {
SuperClass.call(this, name);
}
var F = function(){};
F.prototype = SuperClass.prototype;
SubClass.prototype = new F();
//以上三行相當(dāng)于
//SubClass.prototype = Object.create(SuperClass.prototype)
var test1 = new SubClass('one');
var test2 = new SubClass('two');
test1.sayHi(); //one
test2.sayHi(); //two
test2.sayBye(); //bye
總結(jié):
最好的繼承方式是寄生組合繼承
function SubClass() {
SuperClass.call(this);
}
SubClass.prototype = Object.create(SuperClass.prototype);