继承是面向对象语言的一个特征,js作为一门基于对象的语言,可以通过原型链来模拟继承.
主要是通过构造函数来模拟类的概念,父级的构造函数拥有共有的属性和方法,子级的构造函数有特有的属性和方法,并通过继承来获取父级的属性和方法.
// 先定义一个父类
function Animal(name,sex) {
// 实例属性
this.name = name;
this.sex = sex;
// 实例方法
this.sleep = function() {
console.log(this.name + '在睡觉呢');
}
}
// 原型方法
Animal.prototype.eat = function(){
console.log('就是要吃好吃的');
}
1.原型链继承
核心: 将父类的实例作为子类的原型
function Dog(color) {
this.color = color;
}
Dog.prototype = new Animal();
// 从父类构造函数中继承的属性只能在原型中去设置和修改
Dog.prototype.name = 'dog';
Dog.prototype.sex = '小公举';
// 实例化一个子类
var dog = new Dog('red');
特点:
- 实例是子类的实例,也是父类的实例
- 可以继承父类原型新增的属性和方法
缺点:
- 要想为子类原型新增属性和方法,必须在将子类原型指向父类实例的操作之后;
- 从父类的构造函数继承来的属性无法通过在实例化的时候传参来设置对应值,只能去原型里面改;(主要缺点)
2.构造函数继承
核心: 借用父类的构造函数来增强子类的实例,等于是复制父类的实例属性给子类
function Dog(color, name, sex) {
Animal.call(this, name, sex);
this.color = color;
}
var dog = new Dog('black','小黑','男');
console.log(dog.name, dog.sex, dog.color, dog.sleep()); // 可以继承到构造函数所有的实例属性与方法
console.log(dog.eat()); // 报错,无法继承原型中的属性和方法
特点: 解决了原型继承中无法直接继承父类实例属性方法的问题(具体看上面缺点描述);
缺点: 无法继承原型中的属性和方法
3.组合继承
核心: 原型继承 + 借用构造函数继承
function Dog(color, name, sex) {
Animal.call(this, name, sex);
this.color = color;
}
Dog.prototype = new Animal();
var dog = new Dog('小黑','男','white');
console.log(dog);
console.log(dog.sleep());
console.log(dog.eat());
特点: 实现了实例属性方法和原型属性方法的双继承,可以传参,可以复用
4.拷贝继承
核心: 把一个对象当中的属性或者方法通过循环遍历的方式放到了另外一个对象当中
function Dog(color, name, sex) {
this.color = color;
var animal = new Animal(name, sex);
for(var key in animal) {
this[key] = animal[key];
}
}
var dog = new Dog('yellow','大黄','女');
console.log(dog);//可以继承到name,sex和sleep,eat这些属性和方法哟~
特点: 可以继承父类实例属性方法以及原型属性方法;
无法获取父类不可枚举的方法(不能通过for in访问到的);