两个年轻人 prototype 和 [[prototype]]

395 阅读3分钟

有人问我马老师发生甚么事了,我说怎么回事,发给我两张截图

我一看,渊莱是左天,有两行代码,给我整懵了......

这里就要区分 [[prototype]]prototype

前者是所有 对象 共有的 Internal slot(ES6文档中的定义);

后者是 函数 的一种属性(普通属性),是由一个函数指向一个对象,引用型的,保存所有实例共享的属性、方法(如 Array.sort 方法);

在 ECMAScript 2020 Language Specification 9.1中,有如下定义

All ordinary objects have an internal slot called [[Prototype]]. The value of this internal slot is either null or an object and is used for implementing inheritance. Data properties of the [[Prototype]] object are inherited (and visible as properties of the child object) for the purposes of get access, but not for set access. Accessor properties are inherited for both get access and set access.

翻译出来给我听听,什么 TXD 叫 prototype,什么 TXD 叫TXD [[prototype]]!!!

Tips:JS在设计的时候,new 运算符后面跟的是构造函数,所以 new Foo() 就是在调用 constructor

所以 [[prototype]] 就指向构造函数,每个对象都有自己的构造函数,沿着构造函数一层层网上找,就叫原型链,原型链的顶端是 Object,而 Object 的原型是 null,链到这里就结束啦。

在规范里,[[prototype]] 叫做 Internal slot1,所有的对象都有,而在 JavaScript 中一切皆对象,所以它处处都有。

翻译翻译,它是描述对象行为的一种伪类/伪属性,比如每个对象都有原型,[[prototype]] 就用来描述对象的这种行为,而它又和普通属性不同,(在语言发展的初期)不对用户开放,所以我称它为伪属性2

你又说,我把对象打印出来,根本没有 [[prototype]] ,年轻人不讲武德,来,骗!

小伙子我告诉你,在浏览器里,[[prototype]] 不好用,__proto__ 好用,前者是规范里的写法,加双中括号表示它是一种 Internal Slot,后者是浏览器环境中,为了操作原型,进行的一种 Polyfill3

翻译翻译,早期 JavaScript 语言不开放用户对原型的访问,于是浏览器自己想了个办法,做出了_proto_,用来访问原型;另外,它是一个访问器属性。在规范的附录B中,也对它进行了描述4

在新的规范中,提供了 Object.getPrototypeOf()Object.setPrototypeOf() 两个新方法,并推荐用这两个方法代替__proto__

prototype,就类似于静态属性/静态方法,我们想让某个对象的所有实例共享一些方法/属性,这样能节省资源,而单纯用构造器做不到这一点,prototype就应运而生啦。在规范的 4.3.1 中是这样说的

Each constructor is a function that has a property named "prototype" that is used to implement prototype-based inheritance and shared properties.

所以,回到开头,这张图里最后两行代码大家也就明白什么意思了吧。 最后一个疑问,为啥 ObjectSetPrototypeOf() 中间没有 .,Node.js 的源码里是这样说的:

阮一峰老师的这篇文章讲的太好了,我写的看不明白的话,建议看这个。

OK,就这。