关于原型链,看完这一篇就够了

这是我参与更文挑战的第9天,活动详情查看: 更文挑战

简单的原型链思路

我们知道,在JS里,大部分的数据类型都是对应的构造函数的实例,比如:对象是Object的实例、函数是Function的实例、字符串是String的实例等,这些实例可以通过__proto__继承它们原型上的方法,而对应的构造函数的prototype指向这个原型,原型的constructor指向了构造函数,那么我们就大概可以画出一个”简单”通用的原型链图:

11111.png

完整原型链思路

prototype为函数所特有,__proto__为对象所特有。

构造函数既是函数又是对象,所以构造函数同时拥有prototype和__proto__,而原型对象只有__proto__。

前面我们已经了解了一个简单的原型链,这时你可能会有疑问,既然构造函数是函数,同时拥有prototype和__proto__,那构造函数Xx()的__proto__指向哪里呢?其实,任何的构造函数都是Function类的实例

我们在前面简单原型链图的基础上,再展开来说:图中的Xx()有两个身份,一个是作为构造函数,一个是作为 Function类的实例。作为构造函数,它的prototype已经指向了原型,而作为Function类的实例,这个构造函数也应该是Function类的实例。类似于下图:

22222.png

又有一个问题,Function也是对象啊,那它的__proto__指向哪里?Function构造函数也是函数,就像Xx()一样,是个函数实例,所以它的__proto__是指向Function的原型,如下图:

33333.png

所以,我们可以得到,一切构造函数,都是Function类的实例,包括Function构造函数本身,这样,我们可以得到,Object构造函数,也应该是Function的实例,它的__proto__也是指向Function的原型,如下图(红线部分):

8888888.png

而Object构造函数又有它的原型和实例:

99999999.png

最后,每个原型对象都指向了Object的原型上,形成原型链:

555555.png

在清楚整个原型链后,我们可以对着上面的图轻易的找出原型链的路线(Xx()可以是任一构造函数),比如:

Function.__proto__===Function.prototype;//true 说明两边指向的地址是同一个地址
String.prototype.__proto__ === Number.__proto__.__proto__;//true 说明两边指向的地址是同一个地址
...
复制代码

instanceof

instanceof主要的实现原理就是只要右边的prototype在左边的原型链上即可(注意,instanceof运算符只能用于对象,不适用原始类型的值)。

leftVal. __ proto __ . __ proto __ …… === rightVal.prototype

Function instanceof Object //true 说明Function可以通过原型链找到Object
复制代码

将方法写在原型里与将方法写在构造函数里有什么不同

  1. 把方法写在原型中比写在构造函数中消耗的内存更小。因为在内存中一个类的原型只有一个,写在原型中的行为可以被所有实例共享,实例化的时候并不会在实例的内存中再复制一份,而写在类中的方法,实例化的时候会在每个实例中再复制一份,所以消耗的内存更高。

  2. 构造函数中定义的属性和方法原型中定义的属性和方法优先级高,如果定义了同名称的属性和方法,构造函数中的将会覆盖原型中的属性和方法。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享