JS的原型是什么鬼?

其实作为一个入行那么久的前端,不应该在这时候才来写这种文章了。不过既然之前没写,今天就来总计一下。

在说原型之前,得先说一下JS关于继承的实现。其实JS的继承跟其他Java或者C++等面向对象实现的继承不一样,JS的继承是通过原型的继承来实现的。也就是说JS的继承是另一种方法。

提到JS的原型,及绕不开三个概念:

  • constructor/构造函数,
  • prototype/原型,
  • proto/原型链。

constructor 构造函数(实例生产者)

构造函数,概念跟面向对象的构造函数一个概念。粗略地说就是“用来产生实例的函数。”每个类都会有一个构造函数。

而在JS当中,所有的函数都是构造函数,只要当它跟new关键字一起使用时,就起到了构造函数的作用。

prototype 原型(模板)

prototype 是每个构造函数产生的时候都会同时产生的一个对象,里面有 constructor 属性,指向函数本身,而函数本身也会有一个prototype属性指向prototype。

我个人理解,用通俗的说法就行,每个函数的产生,都会有一个对应的数据结构产生,这个东西就叫prototype(原型),相当于一个模板。每次new一个实例的时候,都会从这个原型上进行一次copy,然后将复制体返回给外面。

所以,当我们在某个function的prototype上挂载方法或者属性时,我们实际上是修改了这个“类”(为了方便理解姑且这么叫吧)的模板。那既然模板都被修改了,所以所有生产出来的实例都会跟着变化啦!

__proto__ 原型链(模板是谁)

既然知道了原型,那这个原型链又是什么东西?

原型链属于实例(相对应的,实例是没有prototype的,只有构造函数才有),用于指向这个实例的构造函数的原型。如果画一个图的话,那么我觉得这个proto可以作为一条线,然后连接实例和它的构造函数的prototype。

也正是有了proto,实例才能够使用prototype上面的属性和方法,否则实例的成员只包含构造函数内声明的属性或者方法。


其实概念就这么简单。只要将上面的几个概念记牢了,面试时面对一些提问的方法,加以套用就能答出正解。

todo 补充一些变体问题