(! [] + []) [+ []] …อธิบายว่าทำไมถึงได้ผล


107
alert((![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]);

ผลลัพธ์ของรหัสนี้คือ: fail. ทำไม?

โดยวิธีการ(![]+[])[+!+[]] == 'false'[1]ใช่มั้ย. แต่ทำไม![]+[] == "false"และทำไม+!+[] == 1?


14
@ สโนบฉันไม่เชื่อใจคุณ ในท้ายที่สุดมันเป็นระเบิดส้อม
Johannes Schaub - litb

3
แน่นอนมันเป็นสตริงตามตัวอักษร;)
Yi Jiang

3
(![]+[])[+[]]คือ "f" (อักขระตัวแรกจาก "เท็จ") (![]+[])[+!+[]]คือ "a" เป็นต้น
Mauricio Scheffer

3
@Snoob: อย่างที่คุณบอกคุณสามารถทดสอบแต่ละนิพจน์บนเบราว์เซอร์ของคุณ ลองalert(![]+[])แล้วalert(+!+[])คุณจะเห็น
Mauricio Scheffer

12
ไม่มีประโยชน์หรือไม่ฉันคิดว่ามันเป็นคำถามที่น่าสนใจและต้องการคำอธิบายที่ดี Code Golf หลายแห่งจะถูกปิดหากพิจารณาถึงประโยชน์หรือการใช้งานจริง แบบฝึกหัดและเกมมีประโยชน์ในตัวเองในการขยายความคิดและกระบวนการคิด
John K

คำตอบ:


127

ตามที่ @Mauricio แสดงความคิดเห็น(![]+[])[+[]]คือ "f" (อักขระตัวแรกของ "false") (![]+[])[+!+[]])คือ "a" ฯลฯ ...

มันทำงานอย่างไร?

ลองตรวจสอบอักขระตัวแรก 'f':

(![]+[])[+[]]; // 'f'

ส่วนแรกของนิพจน์ - ระหว่างวงเล็บ - ประกอบด้วย![]+[]ตัวถูกดำเนินการตัวแรกของตัวดำเนินการการเพิ่มคือ![]และจะสร้างfalseขึ้นเนื่องจากอ็อบเจ็กต์อาร์เรย์ - เช่นเดียวกับอินสแตนซ์ออบเจ็กต์อื่น ๆ เป็นความจริงและการใช้ตรรกะ (!) ไม่ใช่ยูนารี ตัวดำเนินการจะสร้างค่าfalseเช่น

![]; // false, it was truthy
!{}; // false, it was truthy
!0;  // true, it was falsey
!NaN;  // true, it was falsey

หลังจากนั้นเรามีตัวถูกดำเนินการที่สองของการเพิ่ม Array ว่าง[]ซึ่งสร้างขึ้นเพื่อแปลงfalseค่าเป็น String เนื่องจากการแสดงสตริงของอาร์เรย์ว่างเป็นเพียงสตริงว่างนั้นเทียบเท่ากับ:

false+[]; // "false"
false+''; // "false"

ส่วนสุดท้ายคู่ของวงเล็บเหลี่ยมหลังวงเล็บเป็นตัวเข้าถึงคุณสมบัติและรับนิพจน์ซึ่งสร้างขึ้นโดยตัวดำเนินการ Unary Plus ที่ใช้กับอาร์เรย์ว่างอีกครั้ง

สิ่งที่ตัวดำเนินการ Unary Plus ทำคือการแปลงประเภทเป็นNumber:

typeof +"20"; // "number"

อีกครั้งหนึ่งสิ่งนี้ถูกนำไปใช้กับ Array ที่ว่างเปล่าและอย่างที่ฉันเคยพูดไปก่อนหน้านี้การแสดงสตริงของ Array เป็นสตริงว่างและเมื่อคุณแปลงสตริงว่างเป็น Number จะถูกแปลงเป็นศูนย์:

+[]; // 0, because
+[].toString(); // 0, because
+""; // 0

ดังนั้นเราจึงสามารถ "ถอดรหัส" นิพจน์ได้ในบางขั้นตอน:

(![]+[])[+[]];
(false+[])[+[]];
(false+'')[+[]];
(false+'')[0];
('false')[0];  // "f"

โปรดทราบว่าการเข้าถึงอักขระโดยใช้เครื่องหมายวงเล็บบนค่าสตริงไม่ได้เป็นส่วนหนึ่งของ ECMAScript 3rd Edition Specification (นั่นคือสาเหตุที่charAtมีวิธีการนี้)

อย่างไรก็ตาม "คุณสมบัติดัชนี" ประเภทนี้ที่แสดงถึงอักขระของสตริงได้รับการกำหนดมาตรฐานบน ECMAScript 5 และก่อนที่จะมีการกำหนดมาตรฐานคุณลักษณะนี้ก็มีให้ใช้งานในเบราว์เซอร์จำนวนมาก (แม้ใน IE8 (โหมดมาตรฐาน))


46
หวังว่านี่จะไม่ใช่คำถามสัมภาษณ์
Inisheer

4
@JTA: ฉันหวังว่ามันจะเป็น ! ฉันจะผ่านไปได้ :-D
Mauricio Scheffer

18
"ฉัน" มาจากไหน?
Josh Stodola

5
@rlemon ไม่มีintประเภทข้อมูลในภาษาอันที่จริงตัวเลขทั้งหมดเป็นรูปแบบ 64 บิตที่มีความแม่นยำสองเท่า (ค่า IEEE 754) แม้ว่าตัวดำเนินการบางตัวจะทำงานภายในด้วยค่าจำนวนเต็ม (เช่นตัวดำเนินการบิต) ผลลัพธ์จะเป็นสองเท่าเสมอ . 'i'มาในตัวอย่างนี้จากundefinedแต่มันอาจจะมาจากInfinityตัวอย่างเช่น: (+!+[]/+[+[]]+[])[!+[]+!+[]+!+[]]=> (1/0+'')[3]=> (Infinity+'')[3]=>'i'
CMS

5
@JoshStodola อืม ~ 3 เดือนต่อมามีการชี้แจงเพิ่มเติม "i" ในกรณีนี้มาจาก "ไม่ได้กำหนด" ใช่ แต่มีเคล็ดลับอื่นที่เกี่ยวข้องที่นี่ concatenates รหัส "เท็จ" กับ "ไม่ได้กำหนด" เพื่อรูปแบบ"falseundefined"(สร้างขึ้นโดยใช้: [![]]+[][[]]) ซึ่งดัชนีของ "ฉัน" คือ 10 ให้+!+[]+[+[]] "10"สิ่งนี้ใช้เพื่อแยก "i" (ดัชนีสตริงสามารถใช้ใน javascript ได้หากสามารถบังคับให้เป็นจำนวนเต็มได้) โครงสร้างสุดท้ายที่ก่อให้เกิด:([![]]+[][[]])[+!+[]+[+[]]]
เอนโทรปี
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.