JavaScript 中的继承
在网课中,老师着重讲解了原型继承,而在javaScript里面还有其他几种不同的继承方式,我们今天在这里拓展一下
1. 原型继承
这是最基本的继承方式,通过让子类的原型对象指向父类的实例来实现继承。
这种方法的缺点:所有子类实例共享同一个父类实例的属性,创建子类实例时无法向父类构造函数传参
function Person() {this.eye = 2this.head = 1}function Woman() {}Woman.prototype = new Person()Woman.prototype.constructor = WomanWoman.prototype.baby = function () {console.log('baby');}const womans = new Woman()console.log(womans);function Man() {}Man.prototype = new Person()Man.prototype.constructor = Manconst mans = new Man()console.log(mans);
2. 构造函数继承(经典继承)
通过在子类构造函数中调用父类构造函数来实现继承。
优点:可以向父类构造函数传递参数,避免了引用类型属性被所有实例共享
缺点:无法继承父类原型上的方法和属性
function Person() {this.eye = 2this.head = 1}function Woman() {}Woman.prototype = new Person()Woman.prototype.constructor = WomanWoman.prototype.baby = function () {console.log('baby');}const womans = new Woman()console.log(womans);function Man() {}Man.prototype = new Person()Man.prototype.constructor = Manconst mans = new Man()console.log(mans);
3. 组合继承(最常用)
结合原型链继承和构造函数继承的优点。
优点:可以继承父类实例属性和原型属性;可以向父类构造函数传递参数;每个新实例引入的构造函数属性是私有的
缺点:调用了两次父类构造函数
function Parent(name) {this.name = name;
}Parent.prototype.sayName = function() {console.log(this.name);
};function Child(name, age) {Parent.call(this, name); // 第二次调用 Parentthis.age = age;
}Child.prototype = new Parent(); // 第一次调用 Parent
Child.prototype.constructor = Child;const child = new Child('Tom', 10);
child.sayName(); // "Tom"
4. 原型式继承
基于已有对象创建新对象
function createObj(o) {function F() {}F.prototype = o;return new F();
}const parent = {name: 'Parent',sayName: function() {console.log(this.name);}
};const child = createObj(parent);
child.name = 'Child';
child.sayName(); // "Child"
5. ES6 类继承
ES6 引入了 class
语法糖,使继承更加清晰。ES6 的类继承实际上是语法糖,底层仍然是基于原型链的实现。
class Parent {constructor(name) {this.name = name;}sayName() {console.log(this.name);}
}class Child extends Parent {constructor(name, age) {super(name); // 调用父类的constructorthis.age = age;}sayAge() {console.log(this.age);}
}const child = new Child('Tom', 10);
child.sayName(); // "Tom"
child.sayAge(); // 10