前言
写本《JavaScript简餐》系列文章的目的是记录在阅读学习《JavaScript高级程序设计(第4版)》一书时出现的各个知识点。虽是对读书的笔记和总结,但是希望它轻量、简洁、犀利,不会引起阅读疲劳,可以在碎片化时间和闲暇之余轻巧地沐浴一下知识点。每篇文章只针对一个小部分进行讲解式的梳理,来达到个人复习总结和分享知识的目的。
一、实现方式
所谓原型链继承就是以原型链的方式来实现对父类的继承,方式很简单:只需要将父类的一个实例赋值给子类的原型对象即可。来看下面的具体代码实例。
二、继承实例
function Person () {
this.name = {
firstName: 'San',
lastName: 'Zhang'
};
this.age = 20;
this.sayName = function () {
console.log(this.name.lastName, this.name.firstName);
}
}
function Student () {
this.school = 'Tsinghua University';
}
Student.prototype = new Person();
let stu = new Student();
stu.sayName();
console.log(`is ${stu.age} years old, student of ${stu.school}.`);
在这里我们定义了两个构造函数:Person和Student。我们希望Student可以继承Person。所以在下面我们将Student的原型对象赋值为了Person的一个实例。再之后我们创建了一个Student的实例,我们就可以访问父类的属性和方法了。虽然原型链是强大的继承工具,但是原型链的继承不是没有问题的。
三、问题所在
1、引用值误修改
原型链继承的第一个问题就是当原型中出现引用值的时候会在所有实例之间共享,从而可能发生对引用值的误修改。来接着看上面的例子,我们稍作修改。
function Person () {
this.name = {
firstName: 'San',
lastName: 'Zhang'
};
this.age = 20;
this.sayName = function () {
console.log(this.name.lastName, this.name.firstName);
}
}
function Student () {
this.school = 'Tsinghua University';
}
Student.prototype = new Person();
let stu1 = new Student();
let stu2 = new Student();
stu1.age = 26;
stu1.name.lastName = 'Wang';
stu2.sayName();
console.log(`is ${stu2.age} years old, student of ${stu2.school}.`);
可以看到,我们创建了两个实例stu1和stu2,我们修改了stu1的age为26,并且修改了其name.lastName为Wang,但是在我们在下面打印stu2的名字的时候,名字变成了Wang san,但是stu2的age却没有因为stu1的改变而跟着变为26,而仍然是20。正因为name是对象,对象是引用值,当stu1的name对象发生变化时由于stu2和stu1共享这个对象属性,所以stu1上的变化会反映在stu2上。
2、子类型实例化时无法给父类构造函数传参
这个问题在这里不多赘述,具体解决方案可以参考下一篇盗用构造函数的方式。
四、总结
以上就是今天要讲的内容,本文仅仅简单介绍了原型链继承的继承方式和其中所存在的问题,至于其问题的解决方案会在下一篇文章里讲到的盗用构造函数中得以体现。撒花~
|