อัปเดตหมายเหตุ: สิ่งนี้ได้รับการแก้ไขใน Chrome 4949
คำถามที่น่าสนใจมาก! มาขุดกัน
สาเหตุที่แท้จริง
รากของความแตกต่างคือวิธีที่ 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 dveloper ทำสิ่งต่อไปนี้ :
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;
}
ดังนั้นโดยพื้นฐานแล้วมันจะทำ a call
บนวัตถุด้วยนิพจน์ การแสดงออกเป็น:
with ((window && window.console && window.console._commandLineAPI) || {}) {
{}+{};// <-- This is your code
}
ดังนั้นอย่างที่คุณเห็นการแสดงออกจะถูกประเมินโดยตรงโดยไม่ต้องใส่วงเล็บปิด
ทำไม Node.js ทำหน้าที่แตกต่าง
แหล่งที่มาของ Node.js แสดงเหตุผลนี้:
// This catches '{a : 1}' properly.
โหนดไม่ได้ทำตัวแบบนี้เสมอไป ที่นี่เป็นที่ที่เกิดขึ้นจริงกระทำที่มีการเปลี่ยนแปลงมัน Ryan ออกความคิดเห็นต่อไปนี้เกี่ยวกับการเปลี่ยนแปลง: "ปรับปรุงวิธีการที่คำสั่ง REPL จะถูก evaled" พร้อมด้วยตัวอย่างของความแตกต่าง
แรด
อัปเดต - OP มีความสนใจในพฤติกรรมของแรด (และทำไมมันมีพฤติกรรมเช่น devtools ของ Chrome และต่างจาก nodejs)
Rhino ใช้เครื่องมือ JS ที่แตกต่างอย่างสิ้นเชิงซึ่งแตกต่างจากเครื่องมือสำหรับนักพัฒนา Chrome และ REPL ของ Node.js ซึ่งทั้งคู่ใช้ V8
นี่คือบรรทัดไปป์พื้นฐานของสิ่งที่เกิดขึ้นเมื่อคุณประเมินคำสั่ง JavaScript กับ Rhino ในเปลือก Rhino
โดยทั่วไป:
Script script = cx.compileString(scriptText, "<command>", 1, null);
if (script != null) {
script.exec(cx, getShellScope()); // <- just an eval
}
เปลือกของแรดเป็นหนึ่งในสามที่ทำสิ่งที่ใกล้เคียงกับของจริงมากที่สุดeval
โดยไม่มีการพัน แรดเป็นที่ใกล้เคียงกับที่เกิดขึ้นจริงeval()
คำสั่งและคุณสามารถคาดหวังว่ามันจะทำตัวเหมือนeval
หากว่า