This is to do with the weird way this
binding works in JavaScript.
[].reverse
is the method reverse
on an empty list. If you call it, through one of:
[].reverse();
[]['reverse']();
([].reverse)();
then it executes with this
bound to the list instance []
. But if you detach it:
x= [].reverse;
x();
it executes with no this
-binding, so this
in the function points to the global (window
) object, in one of JavaScript's worst, most misleading design mistakes.
(x=[].reverse)()
Is also doing the detach. The assignment operator returns the same function object it was passed so it looks like it's doing nothing, but it has the side-effect of breaking the limited special case that causes JavaScript to bind this
.
So you are saying:
Array.prototype.reverse.call(window)
reverse
, like many other Array.prototype
methods, is defined by ECMAScript to work on any native sequence-like object. It reverses the items with number-string keys (up to object.length
) and returns the object. So it'll return the object that was passed in for any type that has a length
property.
window
has a length property, which corresponds to window.frames.length
, so calling this method with this
pointing at window
will work and return the window
. In theory it may still fail, because:
window
is allowed to be a “host object” rather than a “native object”; in this case the guarantees about what you can pass to other prototypes' methods don't necessarily apply; and
- if the window actually has frames/iframes, it would try to reverse their order, which wouldn't work because the frame collection is read-only.
However, in current browsers the former case does work and the latter fails silently without an error, so you still get the ===window
behaviour and not an Exception.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…