继承的概念
父类的属性和方法可以被子类继承,子类可以调用父类的属性和方法
原型链继承(Prototype Inheritance)
原型链继承是 JavaScript 中一种常见的继承方式,它基于原型链的特性。每个对象都有一个原型对象,对象可以通过原型链访问和继承其他对象的属性和方法。当一个对象被用作另一个对象的原型时,后者可以访问前者的属性和方法。这种继承方式并不会盗用或共享父类的全部内容,而是建立一个链接,使子类对象可以在父类的原型链上查找并继承属性和方法。
举例:
// 父类
function Parent() {
this.name = 'Parent';
}
Parent.prototype.sayHello = function() {
console.log('Hello, I am ' + this.name);
};
// 子类
function Child() {
this.name = 'Child';
}
Child.prototype = new Parent();
var child = new Child();
child.sayHello(); // 输出: Hello, I am Child
在上述代码中,子类 Child 通过 Child.prototype = new Parent() 实现了原型链继承父类 Parent。因此,当 child 对象调用 sayHello 方法时,它会首先在自身的属性和方法中查找,如果找不到,则会沿着原型链向上查找,最终在父类的原型上找到了 sayHello 方法并执行。
原型链继承是通过建立一个原型链,使子类对象可以在父类的原型链上查找并继承属性和方法。
优点:
- 非常纯粹的继承关系,实例是子类的实例,也是父类的实例
- 父类新增原型方法和属性,子类都能访问到
- 简单易于实现
缺点
- 因为原型对象的属性是共享的,修改原型上的一个属性,其他对象的该属性也变了
- 创建子类实例时,无法向父类构造函数传递参数
构造函数继承 (Constructor Inheritance)
构造函数继承是通过调用父类的构造函数来创建子类的实例。这样子类可以继承父类构造函数中定义的属性和方法。在这种继承方式下,子类会拥有自己的实例和方法,但无法访问父类构造函数外部定义的方法。
举例:
function Parent(name) {
this.name = name
}
Parent.prototype.sayHello = function() {
console.log('Hello, I am ' + this.name)
}
function Child(name) {
Parent.call(this, name)
this.age = 10
}
var child = new Child('John')
console.log(child.name) // 输出: John
console.log(child.age) // 输出: 10
child.sayHello() // 报错:child.sayHello is not a function
在上述代码中,子类 Child 在其构造函数中调用了父类 Parent 的构造函数,并传递了相应的参数。这样,子类实例就可以继承父类构造函数中的属性,如 name 和 age。
构造函数继承是通过调用父类的构造函数(function Parent(){})来创建子类的实例,子类可以继承父类构造函数中定义的属性和方法,但无法访问父类构造函数外部定义的方法。
优点:
- 解决了子类实例共享父类引用属性的问题
- 创建子类实例时,可以向父类构造函数传递参数
缺点:
- 无法实现复用,对每一个子类实例都有一个新的 run 函数,如果实例对象多了,内存消耗过大
组合继承(Combination Inheritance)
组合继承是将原型链继承和构造函数继承结合起来的一种方式。它通过在子类的构造函数中调用父类的构造函数,继承父类的属性,并且使用原型链继承方式继承父类的方法。这种方式既可以拥有独立的实例和方法,也可以访问父类构造函数外部定义的方法。
举例:
function Parent(name) {
this.name = name;
}
Parent.prototype.sayHello = function() {
console.log('Hello, I am ' + this.name);
};
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
var child = new Child('John', 10);
console.log(child.name); // 输出: John
console.log(child.age); // 输出: 10
child.sayHello(); // 输出: Hello, I am John
子类 Child 在其构造函数中使用 Parent.call(this, name) 调用了父类 Parent 的构造函数,并传递了相应的参数,从而实现了继承父类的属性。然后,我们将子类 Child 的原型设置为父类 Parent 的实例,这样子类就可以继承父类原型上的方法。最后,我们还需要将子类 Child 的构造函数指向自身,以确保正确设置构造函数的引用。
组合继承是将原型链继承和构造函数继承结合起来的一种方式。它通过在子类的构造函数中调用父类的构造函数,继承父类的属性,并且使用原型链继承方式继承父类的方法。这种方式既可以拥有独立的实例和方法,也可以访问父类构造函数外部定义的方法。
优点:
- 不存在引用属性共享的问题
- 可传递参数,且方法可复用
缺点
- 子类原则上有一份多余的父类实例的属性
class 的 extends 继承
新手写文,多多包涵,如有错误,欢迎指正