1、原型继承
function Animal() {
this.color = ['black','white']
}
Animal.prototype.getColor = function(){
return this.color
}
function Dog() {}
Dog.prototype = new Animal()
let dog1 = new Dog()
dog1.colors.push('brown')
let dog2 = new Dog()
console.log(dog2.colors)
原型链继承存在的问题:
- 问题1:原型中包含的引用类型属性将被所有实例共享;
- 问题2:子类在实例化的时候不能给父类构造函数传参;
2、借用构造函数实现继承
function Animal(name) {
this.name = name
this.getName = function () {
return this.name
}
}
function Dog(name) {
Animal.call(this, name)
}
Dog.prototype = new Animal()
借用构造函数实现继承解决了原型链继承的 2 个问题:引用类型共享问题以及传参问题;
但是由于方法必须定义在构造函数中,所以会导致每次创建子类实例都会创建一遍方法;
3、组合继承
function Animal(name) {
this.name = name
this.colors = ['black', 'white']
}
Animal.prototype.getName = function () {
return this.name
}
function Dog(name, age) {
Animal.call(this, name)
this.age = age
}
Dog.prototype = new Animal()
Dog.prototype.Constructor = Dog
let dog1 = new Dog('奶昔', 2)
dog1.colors.push('brown')
let dog2 = new Dog('哈赤', 1)
console.log(dog2)
优点:融合原型链继承和构造函数的优点,是 JavaScript 中最常用的继承模式。
缺点:调用了两次构造函数,做了重复的操作。
4、寄生组合继承
// 原型链继承 + 构造函数继承
// 1. 引用类型被改变,所有实例共享
// 2. 无法传参
// 3. 多占用了内存空间
function Parent(name, actions) {
this.name = name;
this.actions = actions;
}
Parent.prototype.getName = function () {
console.log(this.name + '调用了getName');
}
function Child() {
Parent.apply(this, arguments);
}
// Child.prototype = Parent.prototype; // 一旦更改Child.prototype,Parent.prototype也会被修改。
Child.prototype = Object.create(Parent.prototype);
// Child.prototype = new Parent();
// let TempFunction = function () {};
// TempFunction.prototype = Parent.prototype;
// Child.prototype = new TempFunction();
Child.prototype.constructor = Child;
// super() Child
const c1 = new Child('c1', ['eat']);
const c2 = new Child('c2', ['run']);