Zaktualizowana uwaga: zostało to naprawione w Chrome 49 .
Bardzo ciekawe pytanie! Zagłębmy się.
Podstawowa przyczyna
Źródłem różnicy jest sposób, w jaki Node.js ocenia te stwierdzenia, w porównaniu z narzędziami programistycznymi Chrome.
Co robi Node.js
Node.js używa do tego modułu repl .
Z kodu źródłowego REPL 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);
}
}
);
Działa to tak samo, jak działanie ({}+{})
w narzędziach programistycznych Chrome, które również działają "[object Object][object Object]"
zgodnie z oczekiwaniami.
Co robią narzędzia programistyczne Chrome
Z drugiej strony narzędzia Chrome dveloper wykonują następujące czynności :
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;
}
Więc zasadniczo wykonuje a call
na obiekcie z wyrażeniem. Wyrażenie to:
with ((window && window.console && window.console._commandLineAPI) || {}) {
{}+{};// <-- This is your code
}
Zatem, jak widać, wyrażenie jest ewaluowane bezpośrednio, bez nawiasów zawijających.
Dlaczego Node.js działa inaczej
Źródło Node.js uzasadnia to:
// This catches '{a : 1}' properly.
Węzeł nie zawsze zachowywał się w ten sposób. Oto faktyczne zatwierdzenie, które go zmieniło . Ryan zostawił następujący komentarz dotyczący zmiany: „Popraw sposób oceny poleceń REPL” z przykładem różnicy.
Nosorożec
Aktualizacja - OP był zainteresowany tym, jak zachowuje się Rhino (i dlaczego zachowuje się jak Devtools Chrome iw przeciwieństwie do nodejs).
Rhino używa zupełnie innego silnika JS w przeciwieństwie do narzędzi programistycznych Chrome i REPL Node.js, które używają V8.
Oto podstawowa rura pokazująca, co się dzieje, gdy oceniasz polecenie JavaScript za pomocą Rhino w powłoce Rhino.
Gruntownie:
Script script = cx.compileString(scriptText, "<command>", 1, null);
if (script != null) {
script.exec(cx, getShellScope()); // <- just an eval
}
Spośród tych trzech, powłoka Rhino jest tą, która jest najbliższa rzeczywistej eval
bez żadnego opakowania. Rhino's jest najbliżej rzeczywistego eval()
stwierdzenia i możesz oczekiwać, że zachowa się dokładnie tak, jak eval
by.