Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Updated note: <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=499864" rel="nofollow noreferrer">this has been fixed in Chrome 49</a>.</p> <p>Very interesting question! Let's dig in.</p> <h2>The root cause</h2> <p>The root of the difference is in how Node.js evaluates these statements vs. how the Chrome development tools do.</p> <h2>What Node.js does</h2> <p>Node.js uses the <a href="http://nodejs.org/api/repl.html" rel="nofollow noreferrer">repl</a> module for this.</p> <p>From the Node.js <a href="https://github.com/joyent/node/blob/master/lib/repl.js#L253" rel="nofollow noreferrer">REPL source code</a>:</p> <pre><code>self.eval( '(' + evalCmd + ')', self.context, 'repl', function (e, ret) { if (e &amp;&amp; !isSyntaxError(e)) return finish(e); if (typeof ret === 'function' &amp;&amp; /^[\r\n\s]*function/.test(evalCmd) || e) { // Now as statement without parens. self.eval(evalCmd, self.context, 'repl', finish); } else { finish(null, ret); } } ); </code></pre> <p>This acts just like running <code>({}+{})</code> in the Chrome developer tools, which also produces <code>"[object Object][object Object]"</code> as you'd expect.</p> <h2>What the chrome developer tools do</h2> <p>On the other hand <a href="https://chromium.googlesource.com/chromium/blink.git/+/master/Source/core/inspector/InjectedScriptSource.js" rel="nofollow noreferrer">Chrome dveloper tools does the following</a>:</p> <pre><code>try { if (injectCommandLineAPI &amp;&amp; inspectedWindow.console) { inspectedWindow.console._commandLineAPI = new CommandLineAPI(this._commandLineAPIImpl, isEvalOnCallFrame ? object : null); expression = "with ((window &amp;&amp; window.console &amp;&amp; window.console._commandLineAPI) || {}) {\n" + expression + "\n}"; } var result = evalFunction.call(object, expression); if (objectGroup === "console") this._lastResult = result; return result; } finally { if (injectCommandLineAPI &amp;&amp; inspectedWindow.console) delete inspectedWindow.console._commandLineAPI; } </code></pre> <p>So basically, it performs a <code>call</code> on the object with the expression. The expression being:</p> <pre><code>with ((window &amp;&amp; window.console &amp;&amp; window.console._commandLineAPI) || {}) { {}+{};// &lt;-- This is your code } </code></pre> <p>So, as you can see, the expression is being evaluted directly, without the wrapping parenthesis.</p> <h2>Why Node.js acts differently</h2> <p>Node.js's source justifies this:</p> <pre><code>// This catches '{a : 1}' properly. </code></pre> <p>Node did not always act like this. Here is <a href="https://github.com/joyent/node/commit/b45698e67629a894cc005efba5c39d0e8adae1b0#lib/repl.js" rel="nofollow noreferrer">the actual commit that changed it</a>. Ryan left the following comment on the change: "Improve how REPL commands are evaled" with an example of the difference.</p> <hr> <h3>Rhino</h3> <p>Update - OP was interested in how <strong>Rhino</strong> behaves (and why it behaves like the Chrome devtools and unlike nodejs).</p> <p>Rhino uses a completely different JS engine unlike the Chrome developer tools and Node.js's REPL which both use V8.</p> <p>Here is the basic pipe line of what happens when you eval a JavaScript command with Rhino in the Rhino shell.</p> <ul> <li><p>The shell runs <a href="https://github.com/mozilla/rhino/blob/master/toolsrc/org/mozilla/javascript/tools/shell/Main.java" rel="nofollow noreferrer"><code>org.mozilla.javascript.tools.shell.main</code></a>.</p></li> <li><p>In turn, it calls <a href="https://github.com/mozilla/rhino/blob/master/toolsrc/org/mozilla/javascript/tools/shell/Main.java#L340" rel="nofollow noreferrer">this</a> <code>new IProxy(IProxy.EVAL_INLINE_SCRIPT);</code> for example, if the code was passed directly with the inline switch -e.</p></li> <li><p>This hits IProxy's <a href="https://github.com/mozilla/rhino/blob/master/toolsrc/org/mozilla/javascript/tools/shell/Main.java#L102" rel="nofollow noreferrer"><code>run</code></a> method.</p></li> <li><p>It invokes <a href="https://github.com/mozilla/rhino/blob/master/toolsrc/org/mozilla/javascript/tools/shell/Main.java#L196-L202" rel="nofollow noreferrer"><code>evalInlineScript</code></a> (<a href="http://paste.ubuntu.com/5801684/" rel="nofollow noreferrer">src</a>). This simply compiles the string and evals it.</p></li> </ul> <p>Basically:</p> <pre><code>Script script = cx.compileString(scriptText, "&lt;command&gt;", 1, null); if (script != null) { script.exec(cx, getShellScope()); // &lt;- just an eval } </code></pre> <p>Out of the three, Rhino's shell is the one that does the closest thing to an actual <code>eval</code> without any wrapping. Rhino's is the closest to an actual <code>eval()</code> statement and you can expect it to behave exactly like <code>eval</code> would.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload