- 原文地址:function.caller considered harmful
- 原文做者:Benedikt Meurer
- 译文出自:掘金翻译计划
- 本文永久连接:github.com/xitu/gold-m…
- 译者:yankwan
- 校对者:Starriers
今天我收到来自微软的 Patrick Kettner 提的这个问题,然而我发现这个问题是我已经回答过的,只不每次的问题稍有不一样而已。前端
最终我发现是本身在第一次看到这个问题的时候理解错了这个问题,而且当别人在 Twitter 上回应的时候我也没有足够重视这个问题。android
最后 Patrick 又提醒我一次,我才发现引发他兴趣的并非 arguments.caller,而是函数对象的 "caller" 这个神秘的属性 ——— 准确来讲是非严格模式下的函数对象。ios
JavaScript 在历史上曾提供了一个有魔力的 foo.caller 属性,它能够返回调用 foo 函数的引用。使用该属性存在着众多问题,例如它可能会因跨域调用产生安全问题、它在复杂的 JavaScript 引擎中实现的不够充分、它难以维护和测试、诸如对闭包的内联插入,逃逸分析和标量替换的优化都变得不可行,甚至在调用 "caller" 的属性访问器时,这些优化在返回的调用函数中也没法实现。git
不少难以想象的事在非严格模式函数中都被限制了。严格模式下函数经过 AddRestrictedFunctionProperties 定义 "caller" 的访问器,当访问该属性的时候会抛出一个类型错误。github
对于非严格模式的函数,目前 EcmaScript 规格中的定义也是很是模糊的,基本上对它没有作任何的规范限制。在章节 16.2 禁止扩展中说到:后端
若是扩展非严格模式或内置函数对象的时候,将对象本身的属性命名为 "caller" ,而且它的值经过 [[Get]] 或者 [[GetOwnProperty]] 定义的话,这种状况下必须保证不是严格模式。若是它是做为一个访问器属性,经过 [[Get]] 属性获取它的值将会返回调用它的函数,那么这个时候不会返回严格模式下的函数。跨域
因此在非严格模式函数下的 "caller" 属性,或多或少彻底实现了既定的行为。惟一的限制是若是有 yield 一个变量,那么这个变量必定不是严格模式下的函数。因此在非严格模式下,给 "caller" 赋一个默认值 42 是一个合理作法。显然实现中并无这么作 —— 尽管有把这个添加到 V8 中的想法,同时如今也极不建议你们使用 foo.caller。安全
这是咱们目前如何在 V8 中实现这些(有误导性的)特性 —— 也正是如何在 Chrome 和 Node.js 中运行的。"caller" 这个属性在非严格模式函数中是一个特殊的访问器,其实现方法 FunctionCallerGetter 在 accessors.cc 源码文件中实现,同时在该文件实现的还有核心的逻辑方法 FindCaller。要理解下面这些规则能够说是比较困难的,但这就是当你在非严格模式下访问 foo.caller时咱们底层代码所作的事:闭包
这里给出了一个它们如何工做的简单例子:ide
如今你对 foo.caller 是怎么工做已经有了一个基本的了解,这里我强烈建议你不要再使用它。正如上述所说的,它基本上是一个不能保证彻底实现的特性。咱们目前仍然会提供支持,但对于 arguments.caller,正如在 crbug.com/691710 提到的同样,咱们可能在某个时间会移除它 —— 由于咱们但愿可以对闭包作逃逸分析和标量替换 —— 因此不要依赖它 —— 同时显然其余 JavaScript 引擎或许根本不支持这种特性。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。