Remarque mise à jour: cela a été corrigé dans Chrome 49 .
Question très intéressante! Allons creuser.
La cause-racine
La racine de la différence réside dans la façon dont Node.js évalue ces déclarations par rapport à la façon dont les outils de développement Chrome le font.
Ce que fait Node.js
Node.js utilise le module repl pour cela.
À partir du code source Node.js 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);
}
}
);
Cela fonctionne comme si vous ({}+{})
exécutiez les outils de développement Chrome, qui produisent également "[object Object][object Object]"
comme vous vous y attendez.
Que font les outils de développement Chrome
D'autre part, les outils de développement Chrome effectuent les opérations suivantes :
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;
}
Donc, fondamentalement, il effectue un call
sur l'objet avec l'expression. L'expression étant:
with ((window && window.console && window.console._commandLineAPI) || {}) {
{}+{};// <-- This is your code
}
Ainsi, comme vous pouvez le voir, l'expression est évaluée directement, sans la parenthèse d'habillage.
Pourquoi Node.js agit différemment
La source de Node.js justifie ceci:
// This catches '{a : 1}' properly.
Node n'a pas toujours agi comme ça. Voici le commit réel qui l'a changé . Ryan a laissé le commentaire suivant sur le changement: "Améliorez la façon dont les commandes REPL sont évaluées" avec un exemple de la différence.
Rhinocéros
Mise à jour - OP était intéressé par le comportement de Rhino (et pourquoi il se comporte comme les outils de développement Chrome et contrairement à nodejs).
Rhino utilise un moteur JS complètement différent, contrairement aux outils de développement Chrome et au REPL de Node.js qui utilisent tous deux la V8.
Voici la ligne de conduite de base de ce qui se passe lorsque vous évaluez une commande JavaScript avec Rhino dans le shell Rhino.
Le shell fonctionne org.mozilla.javascript.tools.shell.main
.
À son tour, il appelle cela new IProxy(IProxy.EVAL_INLINE_SCRIPT);
par exemple, si le code a été transmis directement avec le commutateur en ligne -e.
Cela frappe IProxy run
méthode .
Il invoque evalInlineScript
( src ). Cela compile simplement la chaîne et l'évalue.
Fondamentalement:
Script script = cx.compileString(scriptText, "<command>", 1, null);
if (script != null) {
script.exec(cx, getShellScope()); // <- just an eval
}
Sur les trois, la coquille de Rhino est celle qui fait la chose la plus proche d'un réel eval
sans aucun emballage. Rhino est le plus proche d'une eval()
déclaration réelle et vous pouvez vous attendre à ce qu'il se comporte exactement comme le eval
ferait.