Aktualisierter Hinweis: Dies wurde in Chrome 49 behoben .
Sehr interessante Frage! Lass uns eintauchen.
Die Grundursache
Die Wurzel des Unterschieds liegt darin, wie Node.js diese Aussagen im Vergleich zu den Chrome-Entwicklungstools bewertet.
Was Node.js macht
Node.js verwendet hierfür das Repl- Modul.
Aus dem REPL-Quellcode von 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);
}
}
);
Dies funktioniert genauso wie das Ausführen ({}+{})
in den Chrome-Entwicklertools, die ebenfalls "[object Object][object Object]"
wie erwartet produzieren.
Was die Chrome-Entwicklertools tun
Auf der anderen Seite führt Chrome Dveloper Tools Folgendes aus :
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;
}
Im Grunde führt es ein call
Objekt mit dem Ausdruck aus. Der Ausdruck ist:
with ((window && window.console && window.console._commandLineAPI) || {}) {
{}+{};// <-- This is your code
}
Wie Sie sehen können, wird der Ausdruck direkt ohne die umschließende Klammer ausgewertet.
Warum Node.js anders verhält
Die Quelle von Node.js rechtfertigt dies:
// This catches '{a : 1}' properly.
Node hat sich nicht immer so verhalten. Hier ist das tatsächliche Commit, das es geändert hat . Ryan hinterließ den folgenden Kommentar zu der Änderung: "Verbessern Sie die Auswertung von REPL-Befehlen" mit einem Beispiel für den Unterschied.
Nashorn
Update - OP war daran interessiert, wie sich Rhino verhält (und warum es sich wie die Chrome-Devtools und im Gegensatz zu NodeJS verhält).
Rhino verwendet eine völlig andere JS-Engine als die Chrome-Entwicklertools und die REPL von Node.js, die beide V8 verwenden.
Hier ist die grundlegende Pipeline, was passiert, wenn Sie einen JavaScript-Befehl mit Rhino in der Rhino-Shell auswerten.
Die Shell läuft org.mozilla.javascript.tools.shell.main
.
Im Gegenzug fordert er dies new IProxy(IProxy.EVAL_INLINE_SCRIPT);
beispielsweise, wenn der Code direkt mit dem Inline - Schalter -en übergeben wurde.
Dies trifft die IProxy- run
Methode.
Es ruft evalInlineScript
( src ) auf. Dadurch wird der String einfach kompiliert und ausgewertet.
Grundsätzlich:
Script script = cx.compileString(scriptText, "<command>", 1, null);
if (script != null) {
script.exec(cx, getShellScope()); // <- just an eval
}
Von den dreien ist Rhinos Muschel diejenige, die einer tatsächlichen Sache am nächsten kommt, eval
ohne sie einzuwickeln. Rhino's kommt einer tatsächlichen eval()
Aussage am nächsten und Sie können erwarten, dass sie sich genau so verhält, wie sie es tun eval
würde.