聊聊JavaScript中实现继承的6种方法
面试官:“你说说 JavaScript 中实现继承有哪几种方法?”
紧张的萌新:“额,class 中用 extends 实现继承,然后...没了...”
面试官:“...”
······
想必绝大部分人一说继承就会想到类中的继承吧,但其实继承可不是 class 的专利,本文将总结,JavaScript 中关于继承的几种方案,其中包括原型链,盗用构造函数、组合式等等,助你力压面试官。
注意:本文比较适合具备一定 JS 进阶基础的同学(不会也没关系,收藏就会了?),涉及知识点有:原型、原型链、构造函数、this指向等。如果文中有不对、疑惑的地方,欢迎在评论区留言指正?
0. 继承
继承是面向对象编程中讨论最多的话题。很多面向对象语言都支持两种继承:接口继承和实现继承。前者只继承方法签名,后者继承实际的方法。 接口继承在 ECMAScript中 是不可能的,因为函数没有签名。实现继承是 ECMAScript 唯一支持的继承方式,而这主要是通过原型链实现的。
1. 原型链继承【方案一】
ECMA-262 把原型链定义为 ECMAScript 的主要继承方式。其基本思想就是通过原型继承多个引用类型的属性和方法。重温一下构造函数、原型和实例的关系:
- 每个构造函数都有一个
prototype
属性指向原型对象 - 所有原型对象自动获得一个名为
constructor
的属性,指回与之关联的构造函数
而实例有一个内部指针指向原型。如果原型是另一个类型的实例呢?那就意味着这个原型本身有一个内部指针指向另一个原型,相应的另一个原型也有一个指针指向另一个构造函数。这样就在实例和原型之间构造了一条原型链。这就是原型链的基本构想。
实现原型链继承涉及如下代码模式
// 定义 Person 构造函数 function Person() { this.name = 'CoderBin' } // 给 Person 的原型上添加 getPersonValue 方法(原型方法) Person.prototype.getPersonValue = function() { return this.name } // 定义 Student 构造函数 function Student() { this.sno = '001' } // 继承 Person — 将 Peson 的实例赋值给 Student 的原型 Student.prototype = new Person() Student.prototype.getStudentValue = function() { return this.sno } // 实例化 Student let stu = new Student() console.log(stu.getPersonValue()) // CoderBin