Pregunta muy interesante! Vamos a profundizar.
La causa raíz
La raíz de la diferencia está en cómo Node.js evalúa estas declaraciones en comparación con lo que el Chrome de desarrollo de herramientas.
Lo que Node.js ¿
Node.js utiliza el repl módulo para esto.
A partir de la Node.js REPL código fuente:
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);
}
});
Este actúa como correr ({}+{})
en las herramientas para desarrolladores de Chrome, que también produce "[object Object][object Object]"
como era de esperar.
Lo que las herramientas para desarrolladores de chrome hacer
En el otro lado de Chrome dveloper herramientas hace lo siguiente:
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;
}
Así que, básicamente, se realiza un call
sobre el objeto con la expresión. La expresión es:
with ((window && window.console && window.console._commandLineAPI) || {}) {
{}+{};// <-- This is your code
}
Así que, como pueden ver, la expresión se evaluted directamente, sin la envoltura paréntesis.
Por qué Node.js actúa de forma diferente
Nodo.js fuente justifica esta:
// This catches '{a : 1}' properly.
Nodo no siempre actúan como este. Aquí está la real se comprometen a que la cambió. Ryan dejó el siguiente comentario en el cambio: "Mejorar la forma en que REPL comandos son evaled" con un ejemplo de la diferencia.
Rhino
Actualización - OP estaba interesado en cómo Rhino se comporta (y por qué se comporta como el Chrome devtools y a diferencia de nodejs).
Rhino utiliza una completamente diferente JS motor a diferencia de las herramientas para desarrolladores de Chrome y el Nodo.js del REPL que tanto el uso de V8.
Aquí es la base de la tubería de la línea de lo que sucede cuando se eval un comando de JavaScript con el Rinoceronte en el Rinoceronte de shell.
Básicamente:
Script script = cx.compileString(scriptText, "<command>", 1, null);
if (script != null) {
script.exec(cx, getShellScope()); // <- just an eval
}
De los tres, el Rinoceronte de la cáscara es la que se hace la cosa más cercana a una real eval
sin ningún tipo de embalaje. Rhino es el más cercano a una real eval()
declaración y usted puede esperar que se comporte exactamente como eval
lo haría.