The following script passes when it executes directly within a <script> tag in an HTML document, but it fails if it executes within a .js file that is src=".." referenced. function runTest() { var fn = function() { window.eval('if (this == window) { alert("Context was NOT retained: FAIL"); } else { alert("Context was retained: PASS"); } '); } fn.call('not window'); } runTest();
I cannot quite reproduce this. For me (using either shipping Safari/WebKit 4.0.4 or a recent local debug build on Mac OS X), this fails regardless of whether the script is inline or loaded from a .js file. But it fails, while it passes in Firefox. Looks evil.
Since 'this == window' generally works, my guess is that this bug is specific to how eval selects a this object.
(In reply to comment #2) > Since 'this == window' generally works That is not correct. 'this == window' is never supposed to be true if the context has been assigned for the function invocation in context to something other than window. var fn = function() { alert(this); }; fn.call('hello world');
I don't think this is a particularly bad bug. Safari's behavior matches Chrome's and Opera's, though it seems to differ from the current version of the ES5 spec. Here is a reduced test showing the behavior difference: (function () { window.eval('log(this)'); }).call("a string"); Firefox prints "a string", which Safari, Chrome, and Opera print "[object DOMWindow]". If you change "window.eval" to "eval", Safari, Chrome, and Opera print "a string". The difference in behavior comes down to a question of what syntax counts as a use of the built-in eval operator, as opposed to a call to the built-in eval function. (Only uses of the built-in eval operator inherit local bindings like 'this'.) In Firefox and the current draft of the ES5 spec, any MemberExpression involving the keyword 'eval' counts as a use of the built-in eval operator. In Safari, Chrome, and Opera, only the Identifier 'eval' counts. The more expansive rule in the ES5 spec seems unwarranted, given the complexity it introduces, but I don't see too much harm in implementing it if anyone feels the urge.
(In reply to comment #4) > If you change "window.eval" to "eval", Safari, Chrome, and Opera print "a > string". > The difference in behavior comes down to a question of what syntax counts as a > use of the built-in eval operator, as opposed to a call to the built-in eval > function. (Only uses of the built-in eval operator inherit local bindings like > 'this'.) > In Firefox and the current draft of the ES5 spec, any MemberExpression > involving the keyword 'eval' counts as a use of the built-in eval operator. In > Safari, Chrome, and Opera, only the Identifier 'eval' counts. > The more expansive rule in the ES5 spec seems unwarranted, given the complexity > it introduces, but I don't see too much harm in implementing it if anyone feels > the urge. Very interesting. I didn't realize there was an eval() outside of window.eval(). Your observations are confirmed, works for me too. Good of you to defer back to the ES spec, as I should've before I posted the bug.
Sounds like WORKSFORME, right?
Per Geoff's comments, we don't match Firefox and the spec, and nobody tested IE. Why WORKSFORME?
> Why WORKSFORME? I must have misunderstood the reports "works for me" statement in Comment #5.
(In reply to Jon Davis from comment #0) > var fn = function() { > window.eval('if (this == window) { alert("Context was NOT retained: FAIL"); } else { alert("Context was retained: PASS"); } '); > } > fn.call('not window'); As of 2021, all major browsers (Safari / Chrome / Firefox) report that context was NOT retained, which matches the current spec: see step 6 of https://tc39.es/ecma262/#sec-function-calls-runtime-semantics-evaluation. Property references do not qualify as direct eval (previously known as "built-in eval operator").