有人能解释一下这个Javascript方法吗?

23

1
对于所有标量 y[].reverse.call(y) === y - kennytm
4
我注意到这种行为... 什么行为? - Cheeso
现在,在更现代的引擎中,这会抛出一个错误,因为Array.prototype.reverse是在严格模式下设置的,其中未定义的this值实际上是undefined,而不再是globalThis(即浏览器中的window,Node.js中的global)。 - Sebastian Simon
1个回答

41

这与 JavaScript 中 this 绑定的奇怪方式有关。

[].reverse

如果在一个空列表上调用reverse方法,会发生什么?通过以下任一方式调用:

[].reverse();
[]['reverse']();
([].reverse)();

那么它将会在将 this 绑定到列表实例 [] 之后执行。但是如果你分离它:

x= [].reverse;
x();

它在没有 this 绑定的情况下执行,因此函数中的 this 指向全局 (window) 对象,这是 JavaScript 中最糟糕、最具误导性的设计错误之一。

(x=[].reverse)()

也在执行 detach 操作。赋值运算符返回了相同的函数对象,所以看起来它似乎没有做任何事情,但它具有打破限制特殊情况的副作用,从而导致 JavaScript 绑定 this 的行为失效。

所以你的意思是:

Array.prototype.reverse.call(window)
reverse方法是Array.prototype中定义的一种用于任何原生序列类型对象的方法。它会将具有数字字符串键(最大为object.length)的项目进行反转并返回该对象。因此,对于任何具有length属性的类型,它都会返回传递进来的对象。 window具有一个长度属性,该属性对应于window.frames.length,因此使用this指向window调用此方法将起作用并返回window对象。理论上,它仍可能失败,因为:
  1. window可能是“宿主对象”而不是“本地对象”。在这种情况下,在其他原型的方法中可以传递什么并不一定适用;以及
  2. 如果窗口实际上有框架/iframe,则它将尝试反转它们的顺序,但由于框架集合是只读的,所以无法进行操作。
然而,在当前浏览器中,前者情况确实可行,后者会默默地失败而不会报错,因此您仍将获得===window的行为,而不是异常。

1
你知道为什么有人会编写这个代码吗?我是说,我当然明白它的效果,但我为什么要把它放在我的代码中呢?它能实现什么目的? - Pointy
4
完全没有什么意思。这只是展示JavaScript的许多意外行为之一。如果我在实际代码中发现了这个问题,我会很担心! - bobince
2
这样做的可能原因是为了检查是否有其他脚本干扰了窗口对象(window = open('http://google.com/')就足够了)。var window = (x=[].reverse)();可以在本地恢复它。 - silviot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接