先写一个父类,代码如下:
// 定义一个父类
function Parent (name) {
// 属性
this.name = name;
// 实例方法
this.sleep = function(){
console.log(this.name + '正在睡觉!');
}
}
// 原型方法
Parent.prototype.eat = function(food) {
console.log(this.name + '正在吃:' + food);
};
1、原型链继承
核心: 将父类的实例作为子类的原型
function Child(){
}
Child.prototype = new Parent();
Child.prototype.name = 'son1';
// Test Code
var son1 = new Child();
console.log(son1.name); //son1
console.log(son1.eat('肉')); //son1正在吃肉
console.log(son1 instanceof Child); //true
console.log(son1 instanceof Parent); //true
特点:
- 实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性
- 简单,易于实现 缺点:
- 无法实现多继承
- 新实例无法向父类构造函数传参
- 所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)
2、构造函数继承
核心: 使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)
function Child(){
Parent.call(this,"son2");
this.age = "12";
}
var son2 = new Child();
console.log(son2.name); //'son2'
console.log(son2.age); //12
特点:
- 可以实现多继承(call多个父类对象)
- 在子实例中可向父实例传参 缺点:
- 只能继承父类构造函数的属性,没有继承父类原型的属性/方法
- 无法实现构造函数的复用。(每次用每次都要重新调用)
- 每个新实例都有父类实例函数的副本,影响性能
3、寄生组合继承
核心: 通过寄生方式(在函数内返回对象然后调用),砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性
function Child(taskName){
Parent.call(this,"son3");
this.task = taskName;
}
Child.prototype = Object.create(Parent.prototype);
//上面这行代码等价于下面这个create
//function create(obj){
//function fn(){};
//fn.prototype = obj;
//return new fn();
//}
//create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.study = function(){
console.log(this.name + "学" + this.task);
}
let son3 = new Child("美术");
console.log(son3.name);
特点: 完美解决了其他继承方式的缺点
缺点: 实现较为复杂