为什么原型链的终点是null,而不是Object.prototype

感觉额外允许Object.prototype.__proto__ 为null没什么用啊,这么设计有什么原因么?图片描述

阅读 12k
4 个回答

首先要明确一点,原型链是指对象的原型链,所以原型链上的所有节点都是对象,不能是字符串、数字、布尔值等原始类型。

另外,规范要求原型链必须是有限长度的(从任一节点出发,经过有限步骤后必须到达一个终点。显然也不能有环。)

那么,应该用什么对象作为终点呢?很显然应该用一个特殊的对象。

好吧,Object.prototype确实是个特殊对象,我们先假设用它做终点。那么考虑一下,当你取它的原型时应该怎么办?即

Object.prototype.__proto__;

应该返回什么?

取一个对象的属性时,可能发生三种情况:

  1. 如果属性存在,那么返回属性的值。

  2. 如果属性不存在,那么返回undefined。

  3. 不管属性存在还是不存在,有可能抛异常。

我们已经假设Object.prototype是终点了,所以看起来不能是情况1。另外,抛出异常也不是好的设计,所以也不是情况3。那么情况2呢,它不存在原型属性,返回undefined怎么样?也不好,因为返回undefined一种解释是原型不存在,但是也相当于原型就是undefined。这样,在原型链上就会存在一个非对象的值。

所以,最佳选择就是null。一方面,你没法访问null的属性,所以起到了终止原型链的作用;另一方面,null在某种意义上也是一种对象,即空对象,因为null一开始就是为表示一个“空”的对象存在的。这样一来,就不会违反“原型链上只能有对象”的约定。

所以,“原型链的终点是null”虽然不是必须不可的,但是却是最合理的。

舉個例子 MDN

chris.__proto__ == Engineer.prototype;
chris.__proto__.__proto__ == WorkerBee.prototype;
chris.__proto__.__proto__.__proto__ == Employee.prototype;
chris.__proto__.__proto__.__proto__.__proto__ == Object.prototype;
chris.__proto__.__proto__.__proto__.__proto__.__proto__ == null;

cris 繼承 Engineer
Engineer 繼承 WorkerBee
WorkerBee 繼承 Employee
Employee 繼承 Object
Object 繼承誰? 他不繼承任何人,他本就實現 Object 的所有屬性方法,所以是 null,也讓 javascript 在追朔原型鏈時知道終點在哪。

存在的原因不是「有用」,而是「合乎理性」。

Object.prototype.__proto__ 如果不是 null 难道要是 undefined

况且原型链是不能有环的(否则遍历原型链是不会有终点的),Object.prototype 是一切对象(除非手工设置 __proto__null)的原型,也就意味着它不能有任何对象作为原型。

综上,Object.prototype.__proto__ 只能为 null,意为这里不该有值。

这一定义没有「用」,却对于 Javascript 的逻辑上完备而言是必须的。

object原型链终点为null
为什么是null
null表示没有对象

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏