继承
在JavaScript中,有六种主要常见的继承方式,下面我会对每一种继承方式进行分析并总结它们的优缺点。
1.原型链继承
原型链继承的概念
在JavaScript中,实现继承主要是依靠原型链来实现的。其基本思想是是利用原型让一个引用类型继承另一个引用类型的属性和方法。
让我们简单回顾一下构造函数、原型和实例的关系:每个构造函数都有一个原型对象prototype,原型对象都包含一个指向构造函数的指针constructor,而实例都包含一个指向原型对象的内部指针__proto__
假如我们让原型对象等于另一个类型的实例,结果会怎么样呢?让我们来看下面这段代码。
function Father() {
this.name = ‘zhang’;
}
Father.prototype.sayName = function() {
console.log(this.name);
}
function Son() {
this.age = 18;
}
// 继承了Father
Son.prototype = new Father();
Son.prototype.sayAge = function() {
console.log(this.age);
}
const xiaoming = new Son();
console.log(xiaoming.sayName()) // ‘zhang’
以上代码,Son继承了Father,而继承是通过创建Father的实例,并将Son.prototype指向new出来的Father实例。实现的本质是重写了原型对象,待之是一个新类型的实例,也就是说,原来存在于Father构造函数中的所有属性和方法,现在也存在于Son.prototype中。
通过上图可知,我们没有使用Son默认提供的原型,而是给它换了一个新原型,这个原型就是Father的实例,其内部还有一个指针,指向Father的原型。由于Son的原型被重写了,所以xiaoming这个实例的constructor属性现在指向的是Father。一句话总结就是Son继承了Father,而Father继承Object,当调用xiaoming.toString()方法时,实际上是调用Object.prototype中的toString方法。
注意:给子类原型添加方法的代码一定要放到替换原型的语句之后
图片替换文本
还有一点需要提醒各位小伙伴们,在使用原型链继承时,千万不能使用对象字面量创建原型方法,因为这样做会重写原型链,来看下面这段代码。
function Father() {
this.name = ‘zhang’;
}
Father.prototype.sayName = function() {
console.log(this.name);
}
function Son() {
this.age = 18;
}
// 继承了Father
Son.prototype = new Father();
Son.prototype = {