Catatan yang diperbarui: ini telah diperbaiki di Chrome 49 .
Pertanyaan yang sangat menarik! Mari kita gali.
Akar penyebabnya
Akar perbedaannya terletak pada cara Node.js mengevaluasi pernyataan ini vs. cara alat pengembangan Chrome melakukannya.
Apa yang dilakukan Node.js
Node.js menggunakan modul repl untuk ini.
Dari kode sumber 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) {
self.eval(evalCmd, self.context, 'repl', finish);
}
else {
finish(null, ret);
}
}
);
Ini berfungsi seperti berjalan ({}+{})
di alat pengembang Chrome, yang juga menghasilkan "[object Object][object Object]"
seperti yang Anda harapkan.
Apa yang dilakukan alat pengembang chrome
Di sisi lain, alat pengembang Chrome melakukan hal berikut :
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;
}
Jadi pada dasarnya, ia melakukan a call
pada objek dengan ekspresi. Ekspresinya adalah:
with ((window && window.console && window.console._commandLineAPI) || {}) {
{}+{};
}
Jadi, seperti yang Anda lihat, ekspresi sedang dievaluasi secara langsung, tanpa tanda kurung pembungkus.
Mengapa Node.js bertindak berbeda
Sumber Node.js membenarkan ini:
Node tidak selalu bertindak seperti ini. Berikut adalah komit sebenarnya yang mengubahnya . Ryan meninggalkan komentar berikut tentang perubahan tersebut: "Perbaiki bagaimana perintah REPL dieval" dengan contoh perbedaannya.
Badak
Pembaruan - OP tertarik pada bagaimana Rhino berperilaku (dan mengapa ia berperilaku seperti devtools Chrome dan tidak seperti nodejs).
Rhino menggunakan mesin JS yang sama sekali berbeda tidak seperti alat pengembang Chrome dan REPL Node.js yang keduanya menggunakan V8.
Berikut adalah pipa saluran dasar tentang apa yang terjadi ketika Anda mengevaluasi perintah JavaScript dengan Rhino di cangkang Rhino.
Pada dasarnya:
Script script = cx.compileString(scriptText, "<command>", 1, null);
if (script != null) {
script.exec(cx, getShellScope());
}
Dari ketiganya, cangkang Rhino adalah yang paling mendekati kenyataan eval
tanpa pembungkus. Rhino adalah yang paling dekat dengan eval()
pernyataan aktual dan Anda dapat mengharapkannya berperilaku persis seperti yang diharapkan eval
.