JavaScript的6种继承
1、原型链继承
缺点:这种继承方式会导致原型被一个实例化对象更改后会影响到其他实例化对象的原型对象,因为它们共用的是同一个原型对象
function SuperType() {
this.superFlag = true;
this.colors = ['red', 'skyblue'];
}
SuperType.prototype.say = function() {
console.log('hi');
};
function SubType() {
this.subType = true;
}
SubType.prototype = new SuperType(); // 此处实现了原型链继承
const subType = new SubType();
console.log(subType.colors); // ['red', 'skyblue']
subType.colors.push('yellow'); // ['red', 'skyblue']
console.log(subType.colors); // ['red', 'skyblue', 'yellow']
subType.say(); // hi
const subType2 = new SubType();
console.log(subType2.colors); // ['red', 'skyblue', 'yellow']
subType2.say(); // hi
2、盗用函数继承
缺点:类构造函数的实例化对象无法继承父类构造函数的原型对象
function SuperType(superFlag) {
this.superFlag = superFlag;
this.colors = ['red', 'skyblue'];
}
SuperType.prototype.say = function() {
console.log('hi');
};
function SubType(superFlag, subType) {
SuperType.call(this, superFlag); // 此处实现继承父类构造函数
this.subType = subType;
}
const subType = new SubType(true, true);
console.log(subType.colors); // ['red', 'skyblue']
subType.colors.push('yellow');
console.log(subType.colors); // ['red', 'skyblue', 'yellow']
try {
subType.say();
} catch (error) {
console.log('无法继承父类构造函数原型对象的方法'); // 此处的代码会被执行
}
const subType2 = new SubType(true, true);
console.log(subType2.colors); // ['red', 'skyblue']
try {
subType2.say();
} catch (error) {
console.log('无法继承父类构造函数原型对象的方法'); // 此处的代码会被执行
}
3、组合继承
缺点:父类构造函数会被调用两次,一次是SuperType.call(this, superFlag),另一次是SubType.prototype = new SuperType()
function SuperType(superType) {
this.superFlag = superType;
this.colors = ['red', 'skyblue'];
}
SuperType.prototype.say = function() {
console.log('hi');
};
function SubType(superFlag, subType) {
SuperType.call(this, superFlag); // 此处实现继承父类构造函数
this.subType = subType;
}
SubType.prototype = new SuperType(); // 此处实现父类构造函数的原型对象
const subType = new SubType(true, true);
console.log(subType.colors); // ['red', 'skyblue']
subType.colors.push('yellow');
console.log(subType.colors); // ['red', 'skyblue', 'yellow']
subType.say(); // hi
const subType2 = new SubType(true, true);
console.log(subType2.colors); // ['red', 'skyblue']
subType2.say(); // hi
4、原型式继承
缺点:
1、无法确定实例化的类型
2、该继承的实例化对象共用同一个对象作为原型对象(父类字只是浅复制,实例化更改自己原型对象,会导致其他实例化对象的原型对象也会改变,因为所有实例化的原型对象指向的都是superType对象)
function object(obj) { // 定义原型式继承函数,该函数等价于Object.create()方法
function F() {};
F.prototype = obj;
return new F();
}
const superType = {
superFlag: true,
colors: ['red', 'skyblue'],
say: function() {
console.log('hi');
}
};
const subType = object(superType); // 此处为原型式继承
console.log(subType.colors); // ['red', 'skyblue']
subType.colors.push('yellow');
console.log(subType.colors); // ['red', 'skyblue', 'yellow']
const subType2 = object(superType);
console.log(subType2.colors); // ['red', 'skyblue', 'yellow']
console.log(subType.__proto__ === subType2.__proto__); // true 原因所有实例的原型对象都指向superType对象
5、寄生式继承
缺点:
1、无法确定实例化的类型
2、该继承的实例化对象共用同一个对象作为原型对象(父类字只是浅复制,实例化更改自己原型对象,会导致其他实例化对象的原型对象也会改变,因为所有实例化的原型对象指向的都是superType对象)
和原型式继承的区别:可以在寄生函数里重写和添加属性跟方法
function object(obj) {
function F() {};
F.prototype = obj;
return new F();
}
function cloneObject(obj) { // 定义寄生函数
const clone = object(obj);
clone.say = function() {
console.log('hi');
}
return clone;
}
const superType = {
superFlag: true,
colors: ['red', 'skyblue'],
say: function() {
console.log('hi2');
}
};
const subType = cloneObject(superType); // 此处为寄生式继承
console.log(subType.colors); // ['red', 'skyblue']
subType.colors.push('yellow');
console.log(subType.colors); // ['red', 'skyblue', 'yellow']
subType.say(); // hi
const subType2 = cloneObject(superType);
console.log(subType2.colors); // ['red', 'skyblue', 'yellow']
console.log(subType.__proto__ === subType2.__proto__); // true 原因所有实例的原型对象都指向superType对象
6、寄生式组合继承
解决了组合继承调用两次父类构造函数的问题
function object(obj) {
function F() {};
F.prototype = obj;
return new F();
}
function inheritPrototype(subType, superType) { // 实现将父类构造函数的原型对象赋值给子类构造函数的原型对象,并把原型对象的constructor指回子类构造函数
const prototype = object(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
}
function SuperType(superFlag) {
this.superFlag = superFlag;
this.colors = ['red', 'skyblue'];
}
SuperType.prototype.say = function() {
console.log('hi');
}
function SubType(subFlag, superFlag) {
SuperType.call(this, superFlag); // 此处实现继承父类构造函数的属性和方法
this.subFlag = subFlag;
}
inheritPrototype(SubType, SuperType); // 此处实现继承父类构造函数的原型对象
const subType = new SubType(true, true);
console.log(subType.colors); // ['red', 'skyblue']
subType.colors.push('yellow');
console.log(subType.colors); // ['red', 'skyblue', 'yellow']
subType.say = function() {
console.log('遮蔽say方法');
};
subType.say(); // 遮蔽say方法
const subType2 = new SubType(true, true);
console.log(subType2.colors); // ['red', 'skyblue']
subType2.say(); // hi