【前端面试】JS中通过原型链和class语法分别实现类的继承
程序员文章站
2022-06-09 21:38:39
...
【前端面试】JS中通过原型链和class语法分别实现类的继承
JS中的
类
本质上是一个
function
类型的对象,这是JS的独特之处。
原型链实现继承
在ES6的class
语法推出之前,要实现类的继承要通过修改原型链来实现:
- 首先定义一个父类,本质上是定义父类的构造函数,其对应的
Person.prototype
会自动被创建
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.setName = function(name) {
this.name = name
}
- 然后定义一个子类,通过在子类中用
call
函数,以子类的身份调用父类的构造函数,实现继承父类的成员变量
function Student (name, age) {
Person.call(this,name,age)
}
这样做还不够,因为父类的成员函数
还没有被继承。可以通过将Student
的prototype
的原型链__proto__
指向Person
的prototype
,来实现这一功能。
Student.prototype = new Person //这里无需入参,参数默认是undefined就行,
// 反正成员变量已经在前一步通过call继承到子类型Student对象上了
// 如果需要调用Student的成员变量,也轮不到沿着原型链找到这个new Person头上
然后试一下功能
const s1 = new Student('Bob', 23)
s1.setName('Tom')
console.log(s1)
看起来大功告成!
但是…还有一个细节没有处理,那就是:Student.prototype.constructor
此刻还指向Person
,而正确的情况是:它应该指向Student本身,因此应该:
Student.prototype.constructor = Student
一个细节
在Student.prototype = new Person
这一步中,我提到了可以不带参数,因为Student
对象本身就有name
和age
属性,只不过是undefined
,因此不会沿着原型链找到new Person上。这里做个简单的测试。
Student.prototype = new Person('Jerry', 100) //改变Student原型链的时候带入参
const student1 = new Student //新建student实例的时候不带入参
console.log(student1.name) //undefined 而不是 Jerry
ES6 class 语法实现继承
要实现和上面的代码一样的逻辑,我们应该这么做:
- 先定义父类Person
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
setName(newName) {
this.name = newName
}
}
然后定义子类Student,继承父类Person
class Student extends Person{
constructor(name, age){
super(name, age)
}
}
测试一下:
const student1 = new Student('Tom', 24)
student1.setName('Jerry')
结果如下:
检查继承关系: