浅谈 JavaScript 原型链

Sep 16, 2023

如果是使用过 C++ 或 Java 这类语言的小伙伴,肯定对 OOP 不陌生。而 JavaScript 没有类,又是怎么样实现继承呢?准确来说,前者是基于类的继承机制,而后者是基于原型的继承机制。

听到这,你可能会反驳,JavaScript 不是有class关键字吗?诚然,ES6 之后引入了class关键字,让 JavaScript 有了“类”。但它更像是一种语法糖,只是简化了语法,本质上还是基于原型。

可以说,是构造函数和原型对象共同组成了 JavaScript 中“类”的概念。为了方便理解,先来看张图。

javascript-class.png

如果我们定义了一个构造函数,那么通过构造函数的prototype属性就能访问到原型对象,而通过原型对象的constructor属性又能访问到构造函数。这就是组成了一个“类”,而构造函数的函数名就是这个“类”的类名。

在此基础上,我们再加上new关键字,就可以创建出一个实例对象了。

javascript-instance

如果将这个实例对象在浏览器的控制台中打印出来,会看到实例对象上有一个[[Prototype]]属性,它指向这个“类”中的原型对象。只不过,我们在编写 js 代码时使用的是__proto__

至此,我已经对 JavaScript 中的“类”有了一个基本的认识。但是,要怎么才能实现文章开头提到的继承呢?刚刚提到的__proto__就是关键。

javascript-prototype-chain

通过__proto__属性,我们能给某个原型对象再指定它的原型。这样能够把一系列的原型对象串起来,也就是所谓的“JavaScript 原型链”。因此,我们也就实现了各个“类”之间的继承。

这么看起来,要实现继承确实挺麻烦的。所以,ES6 也给我们提供了更加方便的语法,我们可以使用classextends关键字来实现“类”的继承。不过归根结底,JavaScript 还是基于原型的继承机制,认识原型链也能帮助我们更好地理解 JavaScript 中的继承。