-
原型链继承
即 子构造函数.prototype = new 父构造函数() // 创建父构造函数 function SuperClass(){ this.name = 'liyajie'; this.age = 25; this.showName = function(){ console.log(this.name); } } // 设置父构造函数的原型 SuperClass.prototype.friends = ['小名', '小强']; SuperClass.prototype.showAge = function(){ console.log(this.age); } // 创建子构造函数 function SubClass(){ } // 实现继承 SubClass.prototype = new SuperClass(); // 修改子构造函数的原型的构造器属性 SubClass.prototype.constructor = SubClass; var child = new SubClass(); console.log(child.name); // liyajie console.log(child.age);// 25 child.showName();// liyajie child.showAge();// 25 console.log(child.friends); // ['小名','小强'] // 当我们改变friends的时候, 父构造函数的原型对象的也会变化 child.friends.push('小王八'); console.log(child.friends);["小名", "小强", "小王八"] var father = new SuperClass(); console.log(father.friends);["小名", "小强", "小王八"] 问题:不能给父构造函数传参 父子构造函数的原型对象之间有共享问题
2.借用构造函数
使用call和apply借用其他构造函数的成员, 可以解决给父构造函数传递参数的问题, 但是获取不到父构造函数原型上的成员.也不存在共享问题
// 创建父构造函数
function Person(name){
this.name = name;
this.freinds = ['小王', '小强'];
this.showName = function(){
console.log(this.name);
}
}
// 创建子构造函数
function Student(name){
// 使用call借用Person的构造函数
Person.call(this, name);
}
// 测试是否有了 Person 的成员
var stu = new Student('Li');
stu.showName(); // Li
console.log(stu.friends); // ['小王','小强']
3.组合继承
借用构造函数 + 原型式继承
// 创建父构造函数
function Person(name,age){
this.name = name;
this.age = age;
this.showName = function(){
console.log(this.name);
}
}
// 设置父构造函数的原型对象
Person.prototype.showAge = function(){
console.log(this.age);
}
// 创建子构造函数
function Student(name){
Person.call(this,name);
}
// 设置继承
Student.prototype = Person.prototype;
Student.prototype.constructor = Student;
上面代码解决了 父构造函数的属性继承到了子构造函数的实例对象上了,
并且继承了父构造函数原型对象上的成员
解决了给父构造函数传递参数问题
4.寄生组合继承
这种继承方式对组合继承进行了优化,组合继承缺点在于继承父类函数时调用了构造函数,我们只需要优化掉这点就行了。
function Parent(value) {
this.val = value
}
Parent.prototype.getValue = function() {
console.log(this.val)
}
function Child(value) {
Parent.call(this, value)
}
Child.prototype = Object.create(Parent.prototype, {
constructor: {
value: Child,
enumerable: false,
writable: true,
configurable: true
}
})
const child = new Child(1)
child.getValue() // 1
child instanceof Parent // true
以上继承实现的核心就是将父类的原型赋值给了子类,并且将构造函数设置为子类,这样既解决了无用的父类属性问题,还能正确的找到子类的构造函数。
5.Class 继承
以上两种继承方式都是通过原型去解决的,在 ES6 中,我们可以使用 class 去实现继承,并且实现起来很简单
class Parent {
constructor(value) {
this.val = value
}
getValue() {
console.log(this.val)
}
}
class Child extends Parent {
constructor(value) {
super(value)
this.val = value
}
}
let child = new Child(1)
child.getValue() // 1
child instanceof Parent // true
class 实现继承的核心在于使用 extends 表明继承自哪个父类,并且在子类构造函数中必须调用 super,因为这段代码可以看成 Parent.call(this, value)。
当然了,之前也说了在 JS 中并不存在类,class 的本质就是函数。
