来自红宝书的几种继承方式
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"] 所有实例引用的都是同一个值
缺点:
- 原型的属性被所有实例共享
- 创建子类时不能向父类传参
2. 借用构造函数继承
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
优点:
- 避免所有实例共享原型的属性
- 可以向父类传参
缺点: - 只能继承父类的实例属性、方法,不能继承原型上的属性、方法
- 方法要在父类构造函数中定义,每次创建子类实例都会创建一个方法的副本。子类实例间的方法相同却不能复用。
3. 组合继承
将原型链继承和借用构造函数继承组合起来使用
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
缺点:
调用了两次父类构造函数,实例和原型有一样的属性的方法。
一个来自于SuperClass.call(this, data);
一个来自于SubClass.prototype = new SuperClass()
4. 原型式继承
利用一个空函数作为中介,进行原型的连接。
//这个操作其实就是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"] 实例共享父类属性
缺点:与原型链继承相同
5. 寄生式继承
和原型式继承一个意思
function createObj (o) {
var clone = Object.create(o);
clone.sayName = function () {
console.log('hi');
}
return clone;
}
缺点:与原型式继承相同
6. 寄生组合继承
利用空函数来连接原型,代替组合继承中的SubClass.prototype = new SuperClass(),减少了一次父类构造调用
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();
//以上三行相当于
//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
总结:
最好的继承方式是寄生组合继承
function SubClass() {
SuperClass.call(this);
}
SubClass.prototype = Object.create(SuperClass.prototype);