Оновлена примітка: це виправлено в 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 роблять наступне :
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.
Вузол не завжди діяв так. Ось фактичний комітет, який його змінив . Райан залишив такий коментар до зміни: "Покращити, як викорінюються команди REPL" із прикладом різниці.
Носоріг
Оновлення - ОП цікавило, як поводиться Rhino (і чому він поводиться як devtools Chrome і на відміну від nodejs).
Rhino використовує зовсім інший двигун JS на відміну від інструментів для розробників Chrome та REPL Node.js, які обидва використовують V8.
Ось основна лінія труби, що відбувається, коли ви використовуєте команду JavaScript з Rhino в оболонці Rhino.
Оболонка працює org.mozilla.javascript.tools.shell.main
.
У свою чергу, він викликає це, new IProxy(IProxy.EVAL_INLINE_SCRIPT);
наприклад, якщо код був переданий безпосередньо за допомогою вбудованого перемикача -e.
Це вражає run
метод IProxy .
Він викликає evalInlineScript
( src ). Це просто компілює рядок і оцінює його.
В основному:
Script script = cx.compileString(scriptText, "<command>", 1, null);
if (script != null) {
script.exec(cx, getShellScope()); // <- just an eval
}
З трьох, оболонка Носорога - це та, яка робить найбільш близьку до фактичної eval
без будь-якого обгортання. Носоріг є найближчим до фактичного eval()
твердження, і ви можете очікувати, що він буде вести себе так, як eval
хотів би.