【发布时间】:2020-01-14 06:55:17
【问题描述】:
在尝试使用已弃用的 "caller" 属性时,我在浏览器中遇到了异常行为。使用了以下浏览器:Google Chrome 79.0.3945.117、Firefox 72.0.1、Edge 44.18362.449.0
让我们从一个基本的例子开始:
function start(){}
start.hasOwnProperty("caller")
谷歌浏览器:true,Firefox:false,Edge:true
事实上,只有在 Firefox 中,每个声明的函数才不会使用自己的“调用者”属性。
在这样的例子中:
function start(){"use strict"};
start.hasOwnProperty("caller")
谷歌浏览器:false,Firefox:false,Edge:false
我们看下面的代码
function a(){b()}
function b(){"use strict";c()}
function c(){console.log(c.caller)}
delete Function.prototype.caller;
a()
我们看到了什么?我们看到 Edge 中只发生了一个错误,谷歌浏览器通过向我们显示 null 值来隐藏它,Firefox 返回 undefined 因为它无法在任何地方找到名为 "caller" 的此类属性。
虽然这种情况在规范中被描述为:
如果实现扩展了任何具有名为“caller”的自有属性的函数对象,则使用 [[Get]] 或 [[GetOwnProperty]] 观察到的该属性的值不能是严格的函数对象。如果它是访问器属性,则作为属性的 [[Get]] 属性值的函数在调用时绝不能返回严格函数。
如果我们执行上面的代码但删除"use strict",那么在谷歌浏览器和Edge中我们会注意到条目console.log (c.caller)给我们一个调用当前函数的函数,如果@中没有"caller"属性987654340@。但是在这种情况下 Firefox 是静默的,并产生与严格模式相同的结果 - "undefined"。
顺便说一句,如果我们去掉这些函数的原型,什么都不会改变:
function a(){b()}
function b(){"use strict";c()}
function c(){console.log(c.caller)}
delete Function.prototype.caller;
Object.setPrototypeOf(a,null);
Object.setPrototypeOf(b,null);
Object.setPrototypeOf(c,null);
a();
使用 Firefox,一切都变得非常简单:
- 在严格模式下
- 没有为函数定义
"caller"属性 - 调用
"caller"属性时,属性取自Function.prototype - 调用
"caller"属性会引发错误。
- 没有为函数定义
- 在正常模式下
- 没有为函数定义
"caller"属性 - 调用
"caller"属性时,属性取自Function.prototype - 调用
"caller"属性不会引发错误。
- 没有为函数定义
虽然 Firefox 也不是那么简单。规范说明如下:https://tc39.es/ecma262/#sec-addrestrictedfunctionproperties。也就是说,规范说您需要在调用时在Function.prototype 中定义有错误的属性。规范清楚地将"caller" 访问器属性定义为包含错误的属性。但是 Firefox 在正常模式下,“调用者”属性似乎要么被覆盖,要么最初在两种类型的代码上定义:严格和不严格。这种行为是 Firefox 实现错误吗?
关于 Google Chrome 和 Edge:
- 在严格模式下
- 没有为函数定义
"caller"属性 - 调用
"caller"属性时,属性取自Function.prototype - 调用“caller”属性会引发错误。
- 没有为函数定义
- 在正常模式下
- 为函数定义了
"caller"属性 - 当调用
"caller"属性时,该属性不是取自Function.prototype(在哪里?) - 调用
"caller"属性不会引发错误。
- 为函数定义了
在这种情况下,最令人费解的是 Google Chrome 和 Edge 如何在删除了 Function.prototype 的情况下获取 "caller" 属性的值(在 Function.prototype 中有一个 "caller" 属性的 getter 和 setter,并且在常规函数中,"caller" 属性既没有 getter 也没有 setter)?
【问题讨论】:
-
Function.prototype.caller 尚未正确指定,请参阅这个冗长的讨论:github.com/tc39/ecma262/issues/562。
-
@evilpie 我知道什么 Function.prototype.caller 没有指定。如果你仔细阅读我的帖子,你会明白我的问题是关于浏览器行为而不是规范。此外,规范对“调用者”属性有许多限制。看起来 Firefox 在正常代码中破坏了它们,它不是在 Function.Prototype.caller 中创建一个带有错误的访问器属性,而是一个带有显示调用当前代码的函数的函数的附件属性。
标签: javascript google-chrome firefox ecmascript-6 microsoft-edge