Обновленное примечание: это было исправлено в Chrome 49.
Очень интересный вопрос! Давайте копаться.
Основная причина
Корень разницы в том, как Node.js оценивает эти операторы по сравнению с инструментами разработки Chrome.
Что делает Node.js
Node.js использует для этого модуль repl.
Из исходного кода 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);
}
}
);
Это действует так же, как запуск ({}+{})
в инструментах разработчика Chrome, который также производит "[object Object][object Object]"
, как и следовало ожидать.
Что делают инструменты разработчика Chrome
С другой стороны, инструменты разработчика Chrome делают следующие:
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;
}
По сути, он выполняет call
на объекте с выражением. Выражение:
with ((window && window.console && window.console._commandLineAPI) || {}) {
{}+{};// <-- This is your code
}
Итак, как видите, выражение вычисляется напрямую, без закрывающих скобок.
Почему Node.js действует иначе
Источник Node.js это оправдывает:
// This catches '{a : 1}' properly.
Node не всегда так поступал. Вот реальный коммит, изменивший его. Райан оставил следующий комментарий к изменению: «Улучшите способ преобразования команд REPL» с примером различия.
Носорог
Обновление - OP интересовался тем, как ведет себя Rhino (и почему он ведет себя как инструменты разработчика Chrome, а не nodejs).
Rhino использует совершенно другой движок JS, в отличие от инструментов разработчика Chrome и REPL Node.js, которые оба используют V8.
Вот основная конвейерная линия того, что происходит, когда вы оцениваете команду JavaScript с помощью Rhino в оболочке Rhino.
Оболочка запускает _8 _.
В свою очередь, он вызывает this new IProxy(IProxy.EVAL_INLINE_SCRIPT);
, например, если код был передан напрямую с помощью встроенного переключателя -e.
Это попадает в run
< / a> метод.
Он вызывает evalInlineScript
(src). Это просто компилирует строку и вычисляет ее.
В основном:
Script script = cx.compileString(scriptText, "<command>", 1, null);
if (script != null) {
script.exec(cx, getShellScope()); // <- just an eval
}
Из этих трех оболочка Rhino является наиболее близкой к реальной eval
без какой-либо упаковки. Rhino ближе всего к реальному eval()
оператору, и вы можете ожидать, что он будет вести себя точно так же, как eval
.
person
Benjamin Gruenbaum
schedule
24.06.2013
{}
может интерпретироваться либо как выражение, либо как объектный примитив в зависимости от контекста. Возможно, код на клиенте и на сервере один и тот же, но он интерпретирует{}
по-разному из-за разного контекста ввода кода. - person Patashu   schedule 24.06.2013rhino
в терминал, который делает то же самое ({} + {}
этоNaN
). - person Ionică Bizău   schedule 24.06.2013eval("x="+input)
, она будет вести себя так, как показано - person John Dvorak   schedule 24.06.2013new Function('return {}+{}')()
возвращает"[object Object][object Object]"
. (По крайней мере, согласно документам) - person Benjamin Gruenbaum   schedule 24.06.2013