说起JavaScript的继承方式,大家能想到那几点呢?
- 原型链继承
- 构造函数继承
- 组合继承
- 原型式继承
- 寄生式继承
- 寄生组合式继承
- ES6继承
首先,我们说来原型继承,这是JS中最常见的一种继承方式,每一个对象都有一个原型对象,通过原型链将属性和方法沿着对象链传递下来。在原型链继承中,通过将子构造函数(Child)的原型对象(Child.prototype)指向父构造函数(Parent)的实例(new Parent),实现了继承。这意味着子对象可以访问父对象原型链上的属性和方法。
function Parent() {
this.name = 'Parent';
}
Parent.prototype.sayHello = function() {
console.log('Hello');
};
function Child() {
this.name = 'Child';
}
Child.prototype = new Parent();
var child = new Child();
child.sayHello(); // Hello
总结: 在这个例子中,Child对象的原型对象被设置为Parent的一个实例。这样,当我们调用child.sayHello()时,它会首先在子对象上查找sayHello方法,然后在父对象原型链上找到并执行该方法。注意:原型链继承的缺点是,所有子对象共享同一个原型对象,对原型对象的修改会影响到所有子对象。
第二,构造函数继承是通过在子构造函数中调用父构造函数来实现继承。在构造函数继承中,通过在子构造函数中使用call()或apply()方法,将父构造函数的上下文设置为子对象的上下文,从而实现继承。
function Parent(name) {
this.name = name;
}
function Child(name) {
Parent.call(this, name) // call
}
var child = new Child('Child');
console.log(child.name); // Child
总结: 在这个例子中,我们通过在Child构造函数内部调用Parent构造函数,并传递子对象特定的参数,实现了继承。注意:构造函数继承只能继承父构造函数的实例属性,无法继承父构造函数的原型对象上的方法。
第三,组合继承结合了原型链继承和构造函数继承,既继承了父构造函数的属性,又继承了父构造函数原型对象上的方法。在组合继承中,通过调用父构造函数的方式实现属性的继承,通过将子构造函数的原型对象指向父构造函数的实例实现方法的继承。
function Parent(name) {
this.name = name;
}
Parent.prototype.sayHello = function() {
console.log('Hello');
};
function Child(name) {
Parent.call(this, name);
}
Child.prototype = new Parent();
var child = new Child('Child');
child.sayHello(); // Hello
总结: 在这个例子中,我们通过调用Parent.call(this, name)来继承父构造函数的属性,并通过Child.prototype = new Parent()将子构造函数的原型对象指向父构造函数的实例,从而实现方法的继承。组合继承的优点是既能够继承父构造函数的属性,又能够继承父构造函数原型对象上的方法。缺点是在创建子对象时会调用两次父构造函数,一次是在设置原型时,一次是在创建子对象时。这样会产生一些不必要的开销。
第四,原型式继承是通过使用一个临时构造函数和Object.create()方法来实现继承
var parent = {
name: 'Parent',
sayHello: function() {
console.log('Hello');
}
}
var child = Object.create(parent);
console.log(child.name); // Parent
child.sayHello(); // Hello
总结: 在这个例子中,我们创建了一个parent对象,然后使用Object.create()方法创建了一个新对象child,并将其原型对象指向parent对象,实现了继承。原型式继承的本质是创建一个新对象,将其原型对象指向另一个已有的对象。这种方式可以实现属性和方法的继承,但是不能传递构造函数的参数。
ES6继承: 在ES6中引入了类的概念,通过class关键字和extends关键字可以实现类的继承。
class Parent {
constructor(name) {
this.name = name;
}
sayHello() {
console.log('Hello');
}
}
class Child extends Parent {
constructor(name) {
super(name);
}
}
总结: 子类使用super关键字调用父类的构造函数,并可以访问父类的属性和方法。ES6类继承提供了更加语法简洁和面向对象的继承方式。