While [] + []
adalah string kosong, [] + {}
is "[object Object]"
, dan {} + []
is 0
. Mengapa {} + {}
NaN?
> {} + {}
NaN
Pertanyaan saya adalah tidak mengapa ({} + {}).toString()
adalah "[object Object][object Object]"
sementara NaN.toString()
adalah "NaN"
, bagian ini memiliki jawaban di sini sudah .
Pertanyaan saya adalah mengapa ini hanya terjadi di sisi klien? Di sisi server ( Node.js ) {} + {}
adalah "[object Object][object Object]"
.
> {} + {}
'[object Object][object Object]'
Meringkas :
Di sisi klien:
[] + [] // Returns ""
[] + {} // Returns "[object Object]"
{} + [] // Returns 0
{} + {} // Returns NaN
NaN.toString() // Returns "NaN"
({} + {}).toString() // Returns "[object Object][object Object]"
var a = {} + {}; // 'a' will be "[object Object][object Object]"
Di Node.js:
[] + [] // Returns "" (like on the client)
[] + {} // Returns "[object Object]" (like on the client)
{} + [] // Returns "[object Object]" (not like on the client)
{} + {} // Returns "[object Object][object Object]" (not like on the client)
javascript
node.js
eval
google-chrome-devtools
web-developer-toolbar
Ionică Bizău
sumber
sumber
{}
bisa diartikan baik sebagai ekspresi atau sebagai objek primitif tergantung pada konteksnya. Mungkin kodenya sama di klien dan di server tetapi menafsirkannya{}
berbeda karena konteks yang berbeda dalam memasukkan kode.Jawaban:
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) { // Now as statement without parens. 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) || {}) { {}+{};// <-- This is your code }
Jadi, seperti yang Anda lihat, ekspresi sedang dievaluasi secara langsung, tanpa tanda kurung pembungkus.
Mengapa Node.js bertindak berbeda
Sumber Node.js membenarkan ini:
// This catches '{a : 1}' properly.
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.
Shell berjalan
org.mozilla.javascript.tools.shell.main
.Pada gilirannya, ia memanggil ini
new IProxy(IProxy.EVAL_INLINE_SCRIPT);
misalnya, jika kode diteruskan langsung dengan sakelar sebaris -e.Ini mengenai
run
metode IProxy .Ini memanggil
evalInlineScript
( src ). Ini hanya mengkompilasi string dan evals itu.Pada dasarnya:
Script script = cx.compileString(scriptText, "<command>", 1, null); if (script != null) { script.exec(cx, getShellScope()); // <- just an eval }
Dari ketiganya, cangkang Rhino adalah yang paling mendekati kenyataan
eval
tanpa pembungkus. Rhino adalah yang paling dekat denganeval()
pernyataan aktual dan Anda dapat mengharapkannya berperilaku persis seperti yang diharapkaneval
.sumber
eval
)evaluateOn
. Di node, semuanya didokumentasikan dengan sangat baik - mereka memiliki modul REPL khusus dengan semua sejarah yang bagus dan nyaman di git, setelah menggunakan REPL sebelumnya pada program saya sendiri, saya tahu di mana mencarinya :) Saya senang Anda menyukainya dan menemukannya itu membantu, tetapi saya berhutang pada pengetahuan saya dengan basis kode ini (dev-tools dan nodejs) daripada kecerdasan saya. Langsung ke sumbernya seringkali selalu menjadi yang termudah.