最近在学习原型和原型链。在控制台里,我遇到了一些不解的现象,代码如图
对于这个__proto__
有些看不明白,为什么不是null,而是Fn的prototype。
而我打印 fn.__proto__.__proto__.__proto__
的结果是我预想的 null。
最近在学习原型和原型链。在控制台里,我遇到了一些不解的现象,代码如图
对于这个__proto__
有些看不明白,为什么不是null,而是Fn的prototype。
而我打印 fn.__proto__.__proto__.__proto__
的结果是我预想的 null。
在 JavaScript 中,每个对象都有一个内部链接,称为 [[Prototype]]
,它指向另一个对象,即该对象的原型。当试图访问一个对象的属性时,如果该对象自身没有这个属性,那么 JavaScript 会在该对象的原型(即 [[Prototype]]
指向的对象)上查找这个属性,这就是原型链的概念。
然而,由于 [[Prototype]]
是一个内部链接,JavaScript 为开发者提供了一个非标准的、但在大多数环境中可用的访问器属性 __proto__
,用于读取和设置 [[Prototype]]
。
对于你的问题,fn
是一个函数对象,它的 __proto__
指向 Function.prototype
,这是因为所有的函数对象都继承自 Function.prototype
。你可以通过 fn.__proto__ === Function.prototype
来验证这一点。
当你打印 fn.__proto__.__proto__
时,你实际上是在查看 Function.prototype
的原型。在 JavaScript 中,Function.prototype
的原型是 Object.prototype
,因此 fn.__proto__.__proto__
指向 Object.prototype
。
至于 fn.__proto__.__proto__.__proto__
为何是 null
,这是因为 Object.prototype
的原型是 null
。在 JavaScript 中,原型链的尽头是 null
,表示原型链的结束。
总结一下,__proto__
和 [[Prototype]]
的关系是:__proto__
是用于访问和设置 [[Prototype]]
的非标准属性。它们之间的关系就像是一个公开的(__proto__
)和一个私有的([[Prototype]]
)接口。
至于为什么在这一层突然没有 [[Prototype]]
而出现了 __proto__
,这实际上是因为 __proto__
是 Object.prototype
的一个属性,而 Object.prototype
本身就是一个对象。所以,当你访问 fn.__proto__.__proto__
时,你实际上是在访问一个对象(即 Object.prototype
),而这个对象有自己的 __proto__
属性。然而,Object.prototype
的原型是 null
,所以 Object.prototype.__proto__
是 null
。
请注意,虽然 __proto__
在许多环境中都可用,但它并不是 JavaScript 的标准属性,因此不建议在生产代码中使用。在需要操作原型链时,应该使用 Object.getPrototypeOf()
和 Object.setPrototypeOf()
方法。
fn
是构造器Fn
的一个实例,故fn
的原型指向Fn.prototype
即Object.getPrototypeOf(fn) === Fn.prototype
,在getPrototypeOf
这个标准API出来之前浏览器通过__proto__
这样一个属性来访问对象的原型,所以fn.__proto__ === Fn.prototype
;
Fn.prototype
是一个对象,所以你可以Fn.prototype.sayHello = function(){}
,对象的构造器就是Object
,通常定义一个对象都是使用字面量{prop: 'value'}
但是其实对象也是可以通过构造器new
出来的,即new Object()
,所以对象的原型({}).__proto__ === Object.prototype
;
fn.__proto__.__proto__.__proto__
翻译就是fn
的原型的原型的原型,也就是网上找三次构造器的prototype
:
1.fn
的原型是Fn.prototype
;
2.Fn.prototype
的原型是Object.prototype
;
3.Object.prototype
的原型是null
8 回答4.6k 阅读✓ 已解决
6 回答3.3k 阅读✓ 已解决
5 回答2.8k 阅读✓ 已解决
6 回答2.3k 阅读
5 回答6.3k 阅读✓ 已解决
4 回答2.2k 阅读✓ 已解决
4 回答2.8k 阅读✓ 已解决
这个跟展示的方法有关。因为
__proto__
不是一个普通的属性,而是一个定义在Object.prototype
上的 accessor property/属性访问器 。(你可以在__proto__
下面看到get __proto__
,set __proto__
)所以
__proto__
并没有出现在每一层 prototype 里,而只出现在了它所定义的位置(Object.prototype.__proto__
),而它的值展示的是它在原始对象(也就是 Fn)上的计算结果,也就是 Fn.prototype 。而
[[Prototype]]
是真正的原型对象。但是 Object.prototype.[[Prototype]] 是 null ,于是在结果中并没有展示。[[Prototype]]
也不是普通的属性,而是一个 internel slot 。它在调试器里的展示策略可能跟普通的属性也不一样。