Nota atualizada: isso foi corrigido no Chrome 49 .
Pergunta muito interessante! Vamos cavar.
A causa raiz
A raiz da diferença está na maneira como o Node.js avalia essas instruções em comparação com o desempenho das ferramentas de desenvolvimento do Chrome.
O que o Node.js faz
O Node.js usa o módulo de substituição para isso.
Desde o Node.js código fonte REPL :
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);
}
}
);
Isso funciona como a execução ({}+{})
nas ferramentas de desenvolvedor do Chrome, que também produzem "[object Object][object Object]"
como você esperaria.
O que as ferramentas de desenvolvedor do Chrome fazem
Por outro lado, as ferramentas do Chrome Dveloper fazem o seguinte :
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;
}
Então, basicamente, ele executa um call
no objeto com a expressão A expressão sendo:
with ((window && window.console && window.console._commandLineAPI) || {}) {
{}+{};// <-- This is your code
}
Portanto, como você pode ver, a expressão está sendo avaliada diretamente, sem o parêntese de quebra automática.
Por que o Node.js age de maneira diferente
A fonte do Node.js justifica isso:
// This catches '{a : 1}' properly.
O nó nem sempre agia assim. Aqui está o commit real que o mudou . Ryan deixou o seguinte comentário sobre a alteração: "Melhore como os comandos REPL são avaliados" com um exemplo da diferença.
Rinoceronte
Atualização - O OP estava interessado em como o Rhino se comporta (e por que ele se comporta como os devtools do Chrome e diferente dos nodejs).
O Rhino usa um mecanismo JS completamente diferente das ferramentas de desenvolvedor do Chrome e do REPL do Node.js., que usam a V8.
Aqui está a linha de tubulação básica do que acontece quando você avalia um comando JavaScript com o Rhino no shell do Rhino.
Basicamente:
Script script = cx.compileString(scriptText, "<command>", 1, null);
if (script != null) {
script.exec(cx, getShellScope()); // <- just an eval
}
Dos três, a concha do Rhino é a que mais se aproxima de um real, eval
sem qualquer acondicionamento. O Rhino's é o mais próximo de uma eval()
afirmação real e você pode esperar que ela se comporte exatamente como eval
faria.