{}[true]เป็น[true]และควรจะเป็น![true]false
แล้วทำไมถึง !{}[true]ประเมินเป็นtrue?
{}[true]เป็น[true]และควรจะเป็น![true]false
แล้วทำไมถึง !{}[true]ประเมินเป็นtrue?
{}[true] === [true]จากคอนโซลนั่นเป็นเพราะมันถือว่า{}เป็นบล็อกโค้ดว่างไม่ใช่วัตถุ
{}และ({})ในคอนโซลของคุณ (หรือ{}[true]และ({})[true]) นอกจากนี้ในขณะที่ไม่มีใครพูดถึงวัตถุ [true] จะถูกประเมินว่าเป็น object ["true"]
คำตอบ:
ผมเชื่อว่าเพราะธรรมดา{}[true]จะแยกเป็นบล็อกที่ว่างเปล่าคำสั่ง (ไม่ได้เป็นตัวอักษรวัตถุ) ตามด้วยอาร์เรย์ที่มีซึ่งเป็นtruetrue
ในทางกลับกันการใช้ตัว!ดำเนินการทำให้ parser ตีความ{}ว่าเป็น object literal ดังนั้นสิ่งต่อไปนี้{}[true]จะกลายเป็นการเข้าถึงแบบสมาชิกที่ส่งคืนundefinedและ!{}[true]เป็นจริงtrue(ตามที่!undefinedเป็นtrue)
undefinedเป็นเท็จ (สิ่งที่เราพึ่งพาบ่อยๆ - if (obj.maybeExists) ...) ดังนั้นมันจึงทำให้เกิดความรู้สึกเชิงตรรกะที่สมบูรณ์แบบซึ่ง!undefinedเป็นความจริง
nullในบางภาษาโดยมี!undefinedค่าเท่ากับundefined. นั่นไม่ใช่กรณีของ Javascript
not undefined( !undefined) ต้องถูกกำหนดไว้ trueหากสิ่งที่ถูกกำหนดไว้แล้วก็มักจะตีความว่าเป็น
เนื่องจาก{}[true]ไม่ส่งคืนtrueแต่undefinedและundefinedได้รับการประเมินเป็นfalse:
'use strict';
var b = {}[true];
alert(b); // undefined
b = !{}[true];
alert(b); // true
{}[true]ในคอนโซลคุณจะได้รับ[true]เนื่องจาก{}ถูกตีความว่าเป็นบล็อกโค้ดว่างไม่ใช่อ็อบเจ็กต์ {}มันคือทั้งหมดที่เกี่ยวกับบริบทและความคลุมเครือของ
{key:"value"}[1,2,3];ยังประเมินถึง[1,2,3]?
key:) และสตริงลิเทอรัล ( "value") ตามด้วยอาร์เรย์ ตัวแยกวิเคราะห์ยังไม่เห็นตัวอักษรของวัตถุ
alert()หรือconsole.log()หรือกำหนดให้ตัวแปรคุณมีการเปลี่ยนแปลงบริบทซึ่งเป็นเหตุผลที่มันไม่ได้ทำงานในลักษณะเดียวกับที่พิมพ์บนของตัวเองในคอนโซล
เพราะ
{}[true]
ประเมินundefinedและเป็น!undefinedtrue
จาก @schlingel:
trueใช้เป็นคีย์และ{}เป็นแผนที่แฮช มีไม่ได้อยู่กับคุณสมบัติที่สำคัญเพื่อให้มันกลับtrue undefinedไม่undefinedเป็นtrueไปตามที่คาดไว้
เซสชันคอนโซล ( Node.js [0.10.17] ):
> {}[true]
undefined
> !{}[true]
true
> [true]
[ true ]
> ![true]
false
>
อย่างไรก็ตามในคอนโซลGoogle Chrome :
> !{}[true]
true
ดังนั้นไม่มีความไม่สอดคล้องกัน คุณอาจใช้ JavaScript VM เวอร์ชันเก่า สำหรับผู้ที่ต้องการหลักฐานเพิ่มเติม:

ด้วยFirefoxมันยังประเมินเป็นtrue:

eval('{}[true]')หรือพิมพ์ลงในคอนโซล แล้วเช่น ALS {}"test"เป็นtestหรือแม้กระทั่งถูก{key:"value"}"test" test
{}[true];(กับ;) ผลตอบแทน[true]สำหรับคุณเพราะที่นี่มันไม่?
สาเหตุของความสับสนเกิดจากความเข้าใจผิดในการยืนยันครั้งแรกของคุณ:
{}[true] คือ [true]
สิ่งที่คุณเห็นเมื่อคุณเรียกใช้มันเป็นผลมาจากความไม่ชัดเจน Javascript มีชุดกฎที่กำหนดไว้สำหรับวิธีจัดการกับความคลุมเครือเช่นนี้และในกรณีนี้จะแบ่งสิ่งที่คุณเห็นว่าเป็นคำสั่ง signle ออกเป็นสองคำสั่งแยกกัน
ดังนั้น Javascript เห็นโค้ดข้างต้นเป็นสองงบเฉพาะกิจการ: ประการแรกมีแล้วมีการแยก{} [true]คำสั่งที่สองคือสิ่งที่ให้ผลลัพธ์[true]แก่คุณ คำสั่งแรก{}ถูกละเว้นอย่างสิ้นเชิง
คุณสามารถพิสูจน์ได้โดยลองทำสิ่งต่อไปนี้:
({}[true])
คือการห่อสิ่งทั้งหมดไว้ในวงเล็บเพื่อบังคับให้ล่ามอ่านเป็นคำสั่งเดียว
undefinedตอนนี้คุณจะเห็นว่าค่าที่แท้จริงของคำสั่งของคุณ (สิ่งนี้จะช่วยให้เราเข้าใจส่วนถัดไปในภายหลัง)
ตอนนี้เรารู้แล้วว่าส่วนเริ่มต้นของคำถามของคุณคือปลาเฮอริ่งแดงดังนั้นเรามาดูส่วนสุดท้ายของคำถาม:
แล้วทำไม! {} [true] ถึงประเมินค่าเป็นจริง?
ที่นี่เรามีคำสั่งเดียวกัน แต่มีการ!ผนวกไว้ด้านหน้า
ในกรณีนี้กฎของ Javascript บอกให้ประเมินสิ่งทั้งหมดเป็นคำสั่งเดียว
อ้างถึงสิ่งที่เกิดขึ้นเมื่อเรารวมข้อความก่อนหน้านี้ไว้ในวงเล็บ undefinedเราได้ คราวนี้เรากำลังทำสิ่งเดียวกันอย่างมีประสิทธิภาพ แต่เอา!หน้ามัน ดังนั้นรหัสของคุณได้ง่ายเป็นซึ่งเป็น!undefinedtrue
หวังว่าจะอธิบายได้เล็กน้อย
มันเป็นสัตว์ร้ายที่ซับซ้อน แต่บทเรียนที่ต้องเรียนรู้ที่นี่คือการใช้วงเล็บรอบคำพูดของคุณเมื่อประเมินในคอนโซลเพื่อหลีกเลี่ยงผลลัพธ์ที่น่ากลัวเช่นนี้
{}[true]เป็นที่ไม่ถูกต้องตรงเพียงคลุมเครือ สามารถตีความได้ว่าเป็น "บล็อกโค้ดว่างตามด้วยอาร์เรย์ลิเทอรัล" หรือ "อ็อบเจ็กต์ลิเทอรัลที่ไม่มีคุณสมบัติซึ่งมีการเข้าถึงคุณสมบัติ" ฉันไม่รู้ว่าในทางเทคนิคเป็นกรณีของ ASI หรือไม่ (หลายภาษาจะไม่ใส่เครื่องหมายอัฒภาค) แต่เป็นการตีความที่คำนึงถึงบริบทซึ่งเป็นหัวใจของปัญหา
{}[true]เป็นtrue" ที่พวกเขากล่าวว่า " {}[true]เป็น[true]" ซึ่งเป็นหนึ่งในสองการตีความที่ถูกต้องของข้อความที่คลุมเครือ
{}[true]คือundefined. ในการค้นหาว่าเขียนสิ่งนี้:
a = {};
a[true] === undefined // true
หรือเพียงแค่:
({})[true] === undefined // true
เรารู้ว่าเป็น!undefinedtrue
จากคำตอบของ @Benjamin Gruenbaum :
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
}
อย่างที่คุณเห็นนิพจน์กำลังได้รับการประเมินโดยตรงโดยไม่มีวงเล็บปิด
สามารถดูข้อมูลเพิ่มเติมได้ในคำถามนี้
คำตอบที่นี่เป็นสิ่งที่ดีนี่คือรายละเอียดของรหัสเทียม:
{}['whatever'] = บล็อกว่าง, NewArray ('อะไรก็ได้') = NewArray ('อะไรก็ได้'){}[true] = บล็อกว่าง, NewArray (จริง) = NewArray (จริง)!{}['whatever'] = LogicalNOT (convertToBool (NewObject.whatever)) = LogicalNOT (convertToBool (undefined)) = LogicalNOT (false) = true({}['whatever']) = การจัดกลุ่ม (NewObject.whatever) = การจัดกลุ่ม (ไม่ได้กำหนด) = ไม่ได้กำหนดสิ่งนี้เกิดขึ้นเนื่องจาก{}ในความหมายของคุณไม่ใช่การนำเสนอตามตัวอักษรObjectแต่เป็นขอบเขตว่างเปล่า (หรือบล็อกโค้ดว่าง):
{ var a = 1 }[true] // [true] (do the same thing)
เพียงแค่ประเมินโค้ดภายในขอบเขตแล้วแสดงอาร์เรย์ของคุณ
และจากไฟล์
!{}[true]
เพียงแค่แปลงเป็น int ขอบเขตนี้และส่งคืนอาร์เรย์เดียวกันจริง ไม่มีการตรวจสอบบูลในรหัสนี้
และหากคุณจะลองตรวจสอบผลลัพธ์{}[true]คุณจะได้รับfalse:
{}[true] -> [true] -> ![true] -> false
เนื่องจากไม่มีขอบเขตใด ๆ อีกแล้ว
ดังนั้น!ในคำถามของคุณให้ทำเช่นเดียวกับ:
!function() {
//...
}
var x = {}; x[true]นี้จะเห็นได้ง่ายขึ้นถ้าคุณทำ
!มันถูกตีความว่าเป็นวัตถุว่างเปล่าไม่ใช่ขอบเขตและนี่คือความคลาดเคลื่อน
{} เป็นวัตถุที่ไม่มีคุณสมบัติ[]ทันทีที่ติดตามวัตถุหมายความว่า "เข้าถึงคุณสมบัติของชื่อนี้" ไม่ใช่ "สร้างอาร์เรย์"trueเป็นบูลีน แต่ถูกใช้เป็นชื่อคุณสมบัติดังนั้นจึงถูกส่งไปยังสตริง ( "true")true(เนื่องจากไม่มีคุณสมบัติ) ดังนั้นจึง{}['true']เป็นundefined!undefinedส่งundefinedไปยังบูลีน ( false)falsetrue{}[true](ไม่มีบริบทอื่น ๆ ) {}คือไม่ได้วัตถุที่มีคุณสมบัติที่ไม่มีมันเป็นการป้องกันรหัสที่ว่างเปล่า
คุณไม่ได้ย้อนกลับค่าของมัน
![true] != [!true]
ตรวจสอบสิ่งนี้: ทำไมถึงเป็นจริง? 'เท็จ': 'จริง' กลับ 'จริง'?
ก่อนอื่นมาสนุกกันเถอะ!:
//----------#01#-----------
{}[true]; //[true]
//----------#02#-----------
var a = {}[true];
console.log(a); //undefined
//----------#03#-----------
{ b: 12345 }[true]; //[true]
//----------#04#-----------
{ b: 12345 }["b"]; //evaluates to ["b"] ?!?
//----------#05#-----------
{ b: 12345 }.b; // "Unexpected token ."
//----------#06#-----------
({ b: 12345 }).b; //12345
//----------#07#-----------
var c = { b: 12345 }.b;
console.log(c); //12345
//----------#08#-----------
var c = { b: 12345 }["b"];
console.log(c); //12345
//----------#09#-----------
{ true: 54321 }[true]; // "SyntaxError: Unexpected token : "
//----------#10#-----------
var d = { true: 54321 }[true]; //No error here ¬¬
console.log(d); //54321
//----------#11#-----------
!{}[true]; // true
1) ที่นี่{}จะแยกวิเคราะห์เป็นบล็อกรหัสว่าง หากไม่มีการกำหนดการปฏิเสธการจัดกลุ่ม (พร้อมวงเล็บ) หรือไวยากรณ์ใด ๆ ที่บ่งชี้ให้ผู้แยกวิเคราะห์ทราบว่านี่{}เป็นตัวอักษรตามตัวอักษรสมมติฐานเริ่มต้นคือคิดว่าเป็นเพียงบล็อกว่างเปล่าที่ไร้ประโยชน์
นี่เป็นข้อพิสูจน์ถึงพฤติกรรมนี้:
{ alert(123) }[true]
โค้ดด้านบนจะแสดงการแจ้งเตือนตามปกติและจะได้รับการประเมิน[true]ในลักษณะเดียวกัน{}[true]คือ
คำสั่งประเภทบล็อกไม่จำเป็นต้องมีเครื่องหมายอัฒภาคตามหลัง
ตัวอย่างเช่น:
for(var i=0; i < 1; i++){}function a(){};alert("Passed here!");if(true){}alert("Passed here too!")
การแจ้งเตือนทั้งสองจะปรากฏขึ้น
ดังนั้นเราจะเห็นว่าคำสั่งบล็อกว่างโดยไม่มีอัฒภาคนั้นถูกต้องและไม่ทำอะไรเลย วิธีนี้เมื่อคุณใส่{}[true]ในเครื่องมือสำหรับนักพัฒนา (หรือ Firebug) Console ค่าประเมินจะเป็นค่าของที่ผ่านมางบการแสดงออก [true]ในกรณีนี้คำสั่งสุดท้ายคือการแสดงออก
2)ในบริบทการกำหนดตัววิเคราะห์จะตรวจสอบให้แน่ใจว่า{}เป็นอ็อบเจ็กต์ลิเทอรัล เมื่อคุณทำ var a = {}[true]คุณจะลบความคลุมเครือและดึงตัวแยกวิเคราะห์ออกซึ่ง{}ไม่ใช่คำสั่งบล็อก
ที่นี่คุณกำลังพยายามหาค่าด้วยคีย์"true"จากวัตถุว่างเปล่า เห็นได้ชัดว่าไม่มีคู่คีย์ - ค่ากับชื่อคีย์นี้ ด้วยวิธีนี้ตัวแปรไม่ได้กำหนดไว้
ECMAScript 5อนุญาตให้คีย์ออบเจ็กต์เป็นคำสงวน ดังนั้นคีย์ต่อไปนี้ถูกต้องตามกฎหมาย:
var obj = {if: 111, for: 222, switch: 333, function: 444, true: 555}
3)คำอธิบายเดียวกันของตัวอย่างที่1 แต่ ... ถ้า{ b: 12345 }ส่วนนั้นถือว่าเป็น block statement ประเภทของb: 12345statement คืออะไร ??
... (?????)
มันเป็นคำสั่งฉลากแล้วคุณเห็นมันมาก่อน ... มันใช้ใน loops switchและใน ลิงค์ที่น่าสนใจเกี่ยวกับคำสั่ง label มีดังนี้1 , (2) [ วิธีที่ดีที่สุดในการแยกจากลูปที่ซ้อนกันใน Javascript? , (3) [ วิธีแบ่งลูปที่ซ้อนกันในจาวาสคริปต์? .
หมายเหตุ:ลองประเมินสิ่งนี้:
{a: 1, b: 2} //=>>>SyntaxError: Unexpected token :
คำสั่งป้ายกำกับไม่สามารถแยกออกจากตัวดำเนินการลูกน้ำได้คุณจะต้องคั่นด้วยเครื่องหมายอัฒภาค สิ่งนี้ถูกต้อง:{a: 1; b: 2}
4)ดูคำอธิบายสำหรับตัวอย่างที่1และ3 ...
5)อีกครั้งหนึ่งเรา{ b: 12345 }ถูกถือว่าเป็นบล็อกรหัสและคุณกำลังพยายามเข้าถึงคุณสมบัติของบล็อกรหัสโดยใช้สัญกรณ์จุดและเห็นได้ชัดว่าสิ่งนี้ไม่ได้รับอนุญาตและตัวแยกวิเคราะห์จะแสดง"Unexpected token :"ข้อยกเว้น
6)รหัสเกือบจะเหมือนกับตัวอย่างข้างต้น แต่โดยรอบ{ b: 12345 }คำสั่งที่มีตัวดำเนินการการจัดกลุ่มนิพจน์ตัวแยกวิเคราะห์จะรู้ว่าเป็นวัตถุ ด้วยวิธีนี้คุณจะสามารถเข้าถึง"b"อสังหาริมทรัพย์ได้ตามปกติ
7)จำตัวอย่างที่2เรามีการมอบหมายที่นี่ตัวแยกวิเคราะห์รู้ว่า{ b: 12345 }เป็นวัตถุ
8)เหมือนกับตัวอย่างข้างต้น แต่แทนที่จะสัญกรณ์ดอทนี่เรากำลังใช้สัญกรณ์วงเล็บ
9)ฉันได้กล่าวไปแล้วว่า"identifier: value"ไวยากรณ์นี้ในคำสั่งบล็อกเป็นป้ายกำกับ แต่คุณต้องรู้ด้วยว่าชื่อป้ายกำกับไม่สามารถเป็นคีย์เวิร์ดที่สงวนไว้ได้ (ตรงข้ามกับชื่อคุณสมบัติออบเจ็กต์) เมื่อเราพยายามกำหนดป้ายกำกับที่เรียกว่า"true"เราได้ไฟล์SyntaxError.
10)อีกครั้งเรากำลังจัดการกับวัตถุ ไม่มีปัญหาในการใช้คำสงวนที่นี่ =)
11)สุดท้ายเรามีสิ่งนี้:!{}[true]
มาแยกสิ่งต่างๆที่นี่:
ก) โดยการทำเช่นการปฏิเสธเราจะแจ้งความ parser ที่{}เป็นวัตถุ
ข) ตามที่ปรากฏในตัวอย่างที่ 2ซึ่งเป็น{}วัตถุที่ไม่ได้มีคุณสมบัติที่เรียกว่าเพื่อให้การแสดงออกนี้จะประเมินtrueundefined
c) ผลลัพธ์สุดท้ายคือการปฏิเสธundefinedมูลค่า จาวาสคริดำเนินการประเภท implicity แปลงและundefinedค่า falsy
ง) ดังนั้นการปฏิเสธfalseคือ ... true!
var o = {}; o[true] === undefined.