为什么要有原型(proto)
我们知道,每一个number都有一个 .toString方法,
1 | (1).toString // '1' |
想一想,每一个number都有一个 .toString方法,那这个方法是怎么储存的呢?
是每创建一个number就给这个number一个 .toString方法吗?
假设我们以后有100万个nuber要创建,那么我们就要给100万个number 100万个 .toString方法,这显然是很大的开销,这是不可接受的。
这时候就需要 原型(proto)来拯救世界了。
这些number的 .toString方法长得都一个样,那么我们应该用一个仓库把 .toString方法装起来,等到要用的时候,所有number到这个仓库去取就行了,这个仓库就是 proto 。
创建number的时候,把这个proto 赋给number(也就是说把同一个proto 仓库给新创建的number),这样我们建了一个仓库,却可以给所有number用。
有仓库当然要使劲用,所以这个 proto 仓库不仅装有 .toString方法,还有valueOf,toFixed等一系列乱七八糟的东西。
原型与原型链
上面把 原型(proto)比喻为一个仓库,是为了说明为什么要有proto,其实还可以做这样的比喻:
小明的原型是人 ,人的原型是动物
小明有四肢和五脏六腑,因为小明的原型(proto)是人,人就必须要有四肢和五脏六腑(类比 number的 proto 有.toString方法),人是动物,必须要会运动。
鹦鹉的原型是鸟, 鸟的原型是动物。
鹦鹉有翅膀,因为鹦鹉的原型是鸟,鸟就必须要有翅膀,鸟是动物,所以鸟会运动。
鹦鹉和小明的原型链分别是
鹦鹉 -> 鸟-> 动物
小明 -> 人-> 动物
而 1 这个number的原型链是
1 -> number -> object
1是number 而number 是 object
在控制台测试一下。
看上图,1的 proto 显示它的构造函数是number
(1的 proto ) 的 proto 显示 (1的 proto ) 的构造函数是Object
那么
1 | (1).__proto__.__proto__.__proto__ //null |
是啥呢,结果是null,null就是这个原型链的终点。
完整的原型链应该是:
1 -> number -> object -> null
至于为什么是null ,点这里了解详情
令人迷糊的 __proto__ 和 prototype
先看这一篇文章(赞美方方~)
然后关于__proto__ 和 prototype 只需记住下面这一条公式就完事了
1 | 对象.__proto__ === 构造函数.prototype |
问题:
Function是对象吗?
是
Function是函数吗?
是
下面套入公式1
Function.__proto__ === Function.prototype //true
结果为true
一切都是公式的变形。