JavaScript继承实现的方式也很多,主要分ES5和ES6的继承的实现
- ES5实现继承主要是基于prototype来实现的
- 原型链继承:用子类的原型链等于父类的实例对象
- 借用构造函数继承(call或者apply的方法来实现继承)
- 组合继承是结合原型链继承和借用构造函数继承
- 寄生组合继承
- ES6继承
- 用class关键字定义类,用extend关键字继承类,⽤super()表示⽗类
原型链继承(易于实现,不能传参)
//父类
function Person(name,age){
this.name = name || 'unknow'
this.age = age || 0
}
//子类
function Student(name){
this.name = name
this.score = 80
}
//继承
Student.prototype = new Person();
var stu = new Student('lucy');
console.log(stu.name); //lucy --子类覆盖父类的属性
console.log(stu.age); // 0 --父类的属性
console.log(stu.score); // 80 --子类自己的属性
但是原型链继承有一个缺点,就是如果属性是引用类型的话,会共享引用类型,请看下面代码:
//父类
function Person(){
this.hobbies = ['music','reading']
}
//子类
function Student(){
}
//继承
Student.prototype = new Person();
var stu1 = new Student();
var stu2 = new Student();
stu1.hobbies.push('basketball');
console.log(stu1.hobbies); // ["music", "reading", "basketball"]
console.log(stu2.hobbies); // ["music", "reading", "basketball"]
我们可以看到,当我们改变stu1的引用类型的属性时,stu2对应的属性也会跟着更改,这就是原型链继承的缺点—引用属性会被所有实例共享。
为了解决原型中包含引用类型值的问题,开始使用借用构造函数:构造函数继承
function SuperType() {
this.colors = ["red", "blue", "green"];
}
function SubType() {
//继承SuperType
SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green"
使用构造函数继承就可以避免引用类型被所有实例共享的问题
//父类
function Person(){
this.hobbies = ['music','reading']
}
//子类
function Student(){
Person.call(this);
}
var stu1 = new Student();
var stu2 = new Student();
stu1.hobbies.push('basketball');
console.log(stu1.hobbies); // ["music", "reading", "basketball"]
console.log(stu2.hobbies); // ["music", "reading"]
组合继承:普通属性使用构造函数继承,函数使用原型链继承。
//父类
function Person(name){
this.hobbies = ['music','reading'];
}
Person.prototype.say = function(){
console.log('i am a person');
}
//子类
function Student(name){
Person.call(this); //构造函数继承(继承属性)
}
Student.prototype = new Person(); //原型继承(继承方法)
var stu1 = new Student('lucy');
var stu2 = new Student('lili');
stu1.hobbies.push('basketball');
console.log(stu1.hobbies); // ["music", "reading", "basketball"]
console.log(stu2.hobbies); // ["music", "reading"]
寄生组合继承:
function SuperType (name) {
this.name = name;
this.colors = ["red", "green", "blue"];
}
SuperType.prototype.sayName = function () {
alert(this.name);
};
function SubType (name, age) {
SuperType.call(this, name);
this.age = age;
}
// 下面这部分替代给子类原型赋值的过程,不调用父类构造函数,直接继承父类原型
var prototype = Object.create(SuperType.prototype);
prototype.constructor = SubType;
SubType.prototype = prototype;
SubType.prototype.sayAge = function () {
alert(this.age);
}
ES6中的class继承:
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y);
this.color = color;
}
toString() {
return this.color + ' ' + super.toString();
}
}
let ins = new ColorPoint(1,2,'red');
console.log( ins.toString() ); /* red [object Object] */