Nota aggiornata: è stato risolto in Chrome 49 .
Domanda molto interessante! Scaviamo dentro.
La causa principale
La radice della differenza sta nel modo in cui Node.js valuta queste affermazioni rispetto a come fanno gli strumenti di sviluppo di Chrome.
Cosa fa Node.js
Node.js utilizza il modulo di sostituzione per questo.
Dal codice sorgente REPL di Node.js :
self.eval(
'(' + evalCmd + ')',
self.context,
'repl',
function (e, ret) {
if (e && !isSyntaxError(e))
return finish(e);
if (typeof ret === 'function' && /^[\r\n\s]*function/.test(evalCmd) || e) {
// Now as statement without parens.
self.eval(evalCmd, self.context, 'repl', finish);
}
else {
finish(null, ret);
}
}
);
Questo funziona esattamente come l'esecuzione ({}+{})
negli strumenti di sviluppo di Chrome, che produce anche "[object Object][object Object]"
come ti aspetteresti.
Cosa fanno gli strumenti per sviluppatori di Chrome
D'altra parte, gli strumenti di Chrome Dveloper eseguono le seguenti operazioni :
try {
if (injectCommandLineAPI && inspectedWindow.console) {
inspectedWindow.console._commandLineAPI = new CommandLineAPI(this._commandLineAPIImpl, isEvalOnCallFrame ? object : null);
expression = "with ((window && window.console && window.console._commandLineAPI) || {}) {\n" + expression + "\n}";
}
var result = evalFunction.call(object, expression);
if (objectGroup === "console")
this._lastResult = result;
return result;
}
finally {
if (injectCommandLineAPI && inspectedWindow.console)
delete inspectedWindow.console._commandLineAPI;
}
Quindi, fondamentalmente, esegue un call
oggetto sull'espressione. L'espressione è:
with ((window && window.console && window.console._commandLineAPI) || {}) {
{}+{};// <-- This is your code
}
Quindi, come puoi vedere, l'espressione viene valutata direttamente, senza la parentesi avvolgente.
Perché Node.js si comporta diversamente
La fonte di Node.js giustifica questo:
// This catches '{a : 1}' properly.
Il nodo non ha sempre agito in questo modo. Ecco il commit effettivo che l'ha modificato . Ryan ha lasciato il seguente commento sulla modifica: "Migliora la valutazione dei comandi REPL" con un esempio della differenza.
Rinoceronte
Aggiornamento: OP era interessato a come Rhino si comporta (e perché si comporta come i devtools di Chrome e diversamente dai nodejs).
Rhino utilizza un motore JS completamente diverso a differenza degli strumenti di sviluppo di Chrome e del REPL di Node.js che utilizzano entrambi V8.
Ecco la linea di base di base di ciò che accade quando si valuta un comando JavaScript con Rhino nella shell di Rhino.
Fondamentalmente:
Script script = cx.compileString(scriptText, "<command>", 1, null);
if (script != null) {
script.exec(cx, getShellScope()); // <- just an eval
}
Dei tre, la conchiglia di Rhino è quella che fa la cosa più vicina a un reale eval
senza alcun avvolgimento. Rhino's è il più vicino a eval()
un'affermazione reale e puoi aspettarti che si comporti esattamente come eval
farebbe.