书接上回,我们发现
console.log(cat.__proto__)
打印展开后的Object.prototype的__proto__
属性不为null,显然不符合常理。本文包含个人的推测及对上述问题的解释。
挖到的坑在这里, ➡ JavaScript中的原型和原型链
问题复现
// 函数
function Animal(name){
this.name = name
}
// 在Animal原型对象上加入 animalSay 方法
Animal.prototype.animalSay = function(say){
console.log(`${this.name}说:${say}`)
}
let cat = new Animal('小猫')
console.log(cat.__proto__)
解释
根据 ECMAScript 规范,访问 __proto__
属性时必须遵循以下步骤:
- 如果对象的 [[Prototype]] 属性为 null,则返回 null。
- 否则,返回 Object.getPrototypeOf(obj) 的结果,其中 obj 是当前对象。
什么意思呢?
先简单说下 Object.getPrototypeOf
Object.getPrototypeOf
是一个 JavaScript 内置方法,它返回指定对象的原型。它的语法如下:
Object.getPrototypeOf(obj)
Object.getPrototypeOf
方法返回的是一个对象的原型,而不是对象本身的属性。因此,如果 obj 参数不是一个对象,则会抛出 TypeError 异常。
下面正式开始解释问题 ⬇
- 首先我们要知道,
Object.prototype
作为 JavaScript 中所有对象的顶层原型,它并没有[[prototype]]
属性! - 没有
[[prototype]]
属性,依据 ECMAScript 规范,意味着在我们位于Object.prototype
处需要访问__proto__
时,第一个条件是直接判定跳过了,紧接的是 js 将会调用Object.getPrototypeOf(当前对象)
方法,意外地又将 Object.prototype的__proto__
指向又指向到Object.prototype中,但事实上__proto__
属性的指向是 null。 - 再后面 个人推测是 js 发现指向不合理,于是对当前对象进行修正,使得最内层
__proto__
指向为null。
// 尝试用 Object.getPrototypeOf 打印输出对象的原型对象
console.log(Object.getPrototypeOf(cat.__proto__))
console.log(Object.getPrototypeOf(cat.__proto__.__proto__))
参杂个人理解,难免有错漏,文章有问题之处还望评论斧正!