อย่างไร !! ~ (ไม่ใช่เครื่องหมายทิลเดอร์ / แบงแบงทิลเดอร์) เปลี่ยนผลลัพธ์ของการเรียกเมธอดอาร์เรย์ 'มี / รวม' อย่างไร


95

หากคุณอ่านความคิดเห็นในinArrayหน้าjQuery ที่นี่มีคำประกาศที่น่าสนใจ:

!!~jQuery.inArray(elm, arr) 

ตอนนี้ฉันเชื่อว่าเครื่องหมายอัศเจรีย์คู่จะแปลงผลลัพธ์เป็นประเภทbooleanโดยมีค่าเป็นtrue. สิ่งที่ฉันไม่เข้าใจคือการใช้ตัวดำเนินการ tilde ( ~) ทั้งหมดนี้คืออะไร?

var arr = ["one", "two", "three"];
if (jQuery.inArray("one", arr) > -1) { alert("Found"); }

การปรับโครงสร้างifคำสั่ง:

if (!!~jQuery.inArray("one", arr)) { alert("Found"); }

ทำให้พังถล่ม:

jQuery.inArray("one", arr)     // 0
~jQuery.inArray("one", arr)    // -1 (why?)
!~jQuery.inArray("one", arr)   // false
!!~jQuery.inArray("one", arr)  // true

-2ฉันยังพบว่าถ้าฉันใส่ตัวหนอนในหน้าผลที่ได้คือ

~!!~jQuery.inArray("one", arr) // -2

ฉันไม่เข้าใจจุดประสงค์ของตัวหนอนที่นี่ ใครช่วยอธิบายหรือชี้ให้ฉันดูแหล่งข้อมูลได้ไหม


50
ใครจะเขียนโค้ดแบบนั้นก็ต้องถอยห่างจากคีย์บอร์ด
Kirk Woll

12
@KirkWoll: ทำไม? ~jQuery.inArray()มีประโยชน์มากจริง ๆ - อาจเป็นเหตุผลที่ดีมากที่ทำให้ฟังก์ชันการค้นหากลับมา-1ล้มเหลว (ค่าเดียวที่ส่วนเติมเต็มของทั้งสองเป็นเท็จ) != -1เมื่อคุณได้เห็นและเข้าใจเคล็ดลับผมรู้สึกว่ามันเป็นยังสามารถอ่านได้มากกว่า
Amadan

9
@ อมะฎอน - น. แค่ไม่. อย่างจริงจังฉันไม่สามารถเชื่อว่าคุณกำลังปกป้อง!!~สำหรับอะไร
Kirk Woll

24
ปัญหาก็แค่นั้น: "เคล็ดลับ" ความแตกต่างที่สำคัญระหว่างif (x != -1)และif (~x)ให้ฉันเป็นว่าอดีตจริงเป็นการแสดงออกถึงสิ่งที่คุณตั้งใจจะทำ คำหลังเป็นการแสดงว่าคุณต้องการทำอย่างอื่นทั้งหมด ("โปรดแปลงหมายเลข 64 บิตของฉันเป็นจำนวนเต็ม 32 บิตและตรวจสอบว่าบิตที่ไม่ใช่จำนวนเต็มนั้นเป็นจริงหรือไม่") ซึ่งคุณเพิ่งได้ผลลัพธ์ที่ต้องการในสิ่งนี้ หนึ่งกรณี
JimmiTh

10
>= 0อาจจะไม่ได้เจ๋งพอดังนั้นคลุมเครือมากขึ้น!!~ถูกนำมาใช้
โยชิ

คำตอบ:


57

ตัวดำเนินการ tilde ไม่ได้เป็นส่วนหนึ่งของ jQuery เลย แต่เป็นตัวดำเนินการที่ไม่ใช่ตัวดำเนินการใน JavaScript

ดูความลึกลับที่ยิ่งใหญ่ของตัวหนอน (~)

คุณได้รับตัวเลขแปลก ๆ ในการทดลองของคุณเนื่องจากคุณกำลังดำเนินการเชิงตรรกะแบบบิตต่อจำนวนเต็ม (ซึ่งสำหรับสิ่งที่ฉันรู้อาจถูกเก็บไว้เป็นส่วนเติมเต็มสองส่วนหรืออะไรทำนองนั้น ...

ส่วนเติมเต็มของ Twoอธิบายถึงวิธีการแทนจำนวนในฐานสอง ฉันคิดว่าฉันคิดถูก


3
แก้ไขแล้ว! (เปลี่ยนเป็นลิงค์อื่นที่เขียนไว้หลังคำตอบเดิมของฉัน ... )
pglhall

121

มีเหตุผลที่คุณจะ specfic บางครั้งดูเป็นนำไปใช้ในด้านหน้าของ~$.inArray

โดยพื้นฐานแล้ว

~$.inArray("foo", bar)

เป็นวิธีที่สั้นกว่า

$.inArray("foo", bar) !== -1

$.inArrayส่งคืนดัชนีของรายการในอาร์เรย์หากพบอาร์กิวเมนต์แรกและส่งกลับค่า -1 หากไม่พบ ซึ่งหมายความว่าหากคุณกำลังมองหาบูลีนของ "ค่านี้อยู่ในอาร์เรย์หรือไม่" คุณจะทำการเปรียบเทียบบูลีนไม่ได้เนื่องจาก -1 เป็นค่าที่แท้จริงและเมื่อ $ .inArray ส่งกลับ 0 (ค่าที่เป็นเท็จ ) หมายถึงพบได้จริงในองค์ประกอบแรกของอาร์เรย์

การใช้ตัว~ดำเนินการแบบบิต-1จะทำให้กลายเป็น0และทำให้ 0 กลายเป็น `-1 ดังนั้นการไม่ค้นหาค่าในอาร์เรย์และการใช้ bitwise จะไม่ส่งผลให้เกิดค่าเท็จ (0) และค่าอื่น ๆ ทั้งหมดจะส่งกลับตัวเลขที่ไม่ใช่ 0 และจะแสดงผลลัพธ์ที่แท้จริง

if (~$.inArray("foo", ["foo",2,3])) {
    // Will run
}

และมันจะทำงานตามที่ตั้งใจไว้


2
สิ่งนี้รองรับในเบราว์เซอร์ได้ดีเพียงใด (ตอนนี้ในปี 2014) หรือได้รับการสนับสนุนอย่างสมบูรณ์แบบตลอดมา
ยาระเบิด

ฉันจะแปลกใจถ้าการทำงานพื้นฐานเช่นนี้ไม่สมบูรณ์แบบ
pcarvalho

105

!!~exprประเมินfalseเมื่อexprเป็นอย่างอื่น-1 ก็เหมือนกับเสียเท่านั้น *true
expr != -1


ทำงานได้เนื่องจากการดำเนินการแบบบิตของ JavaScriptแปลงตัวถูกดำเนินการเป็นจำนวนเต็มที่ลงนาม 32 บิตในรูปแบบส่วนเติมเต็มของสอง จึง!!~-1มีการประเมินดังนี้:

   -1 = 1111 1111 1111 1111 1111 1111 1111 1111b // two's complement representation of -1
  ~-1 = 0000 0000 0000 0000 0000 0000 0000 0000b // ~ is bitwise not (invert all bits)
   !0 = true                                     // ! is logical not (true for falsy)
!true = false                                    // duh

ค่าอื่นที่ไม่ใช่-1จะมีอย่างน้อยหนึ่งบิตตั้งเป็นศูนย์ การกลับด้านจะสร้างมูลค่าที่แท้จริง การใช้!ตัวดำเนินการสองครั้งกับค่าที่แท้จริงจะส่งกลับค่าบูลีนจริง

เมื่อใช้กับ.indexOf()และเราต้องการตรวจสอบว่าผลลัพธ์เป็น-1หรือไม่เท่านั้น:

!!~"abc".indexOf("d") // indexOf() returns -1, the expression evaluates to false
!!~"abc".indexOf("a") // indexOf() returns  0, the expression evaluates to true
!!~"abc".indexOf("b") // indexOf() returns  1, the expression evaluates to true

* !!~8589934591ประเมินเป็นเท็จดังนั้นสิ่งนี้สิ่งที่น่ารังเกียจ-1ไม่สามารถใช้งานได้อย่างน่าเชื่อถือในการทดสอบสำหรับ


1
ในไลบรารีที่เสถียรฉันไม่เห็นปัญหาในการใช้~foo.indexOf(bar)งานมันไม่ได้ช่วยประหยัดตัวละครหรือประสิทธิภาพได้อย่างมีนัยสำคัญ แต่เป็นชวเลขที่พบได้บ่อยในลักษณะเดียวกับที่foo = foo || {}เป็น
zzzzBov

6
ไม่ใช่ปัญหา ... อย่างน้อยก็จนกว่าจะมีคนขอให้ดำเนินการต่อด้วยรหัสของคุณ
Salman A


1
@ahsteele ฉันทราบดีถึงกฎนั้น แต่ตัวดำเนินการระดับบิตเป็นส่วนหนึ่งของภาษาโปรแกรมทุกภาษาที่ฉันคิดได้ ฉันพยายามตั้งโปรแกรมให้คนที่อ่านโค้ดอ่านได้ ฉันไม่หยุดใช้คุณลักษณะของภาษาเพียงเพราะมีคนอื่นไม่เข้าใจมิฉะนั้นฉันจะใช้ไม่ได้!!ด้วยซ้ำ
zzzzBov

พูดอย่างเคร่งครัด>= 0ไม่มีพฤติกรรมเช่นเดียวกับ!!~. !== -1อยู่ใกล้กว่า
Peter Olson

33

~foo.indexOf(bar)เป็นชวเลขทั่วไปที่ใช้แทนfoo.contains(bar)เนื่องจากcontainsไม่มีฟังก์ชันอยู่

โดยทั่วไปแล้วการแคสต์ไปยังบูลีนนั้นไม่จำเป็นเนื่องจากแนวคิดของ JavaScript เกี่ยวกับค่า "เท็จ" ในกรณีนี้จะใช้ในการบังคับให้การส่งออกของฟังก์ชั่นที่จะเป็นหรือtruefalse


6
+1 คำตอบนี้อธิบาย "ทำไม" ได้ดีกว่าคำตอบที่ยอมรับ
nalply

18

jQuery.inArray()ผลตอบแทน-1สำหรับ "ไม่พบ" ซึ่งมีส่วนประกอบ ( ~) 0เป็น ดังนั้น~jQuery.inArray()ส่งคืนค่าเท็จ ( 0) สำหรับ "not found" และค่าจริง (จำนวนเต็มลบ) สำหรับ "found" !!จากนั้นจะทำพิธี falsy / truthy เข้าจริงบูล/false trueดังนั้น!!~jQuery.inArray()จะให้trueสำหรับ "พบ" และfalseสำหรับ "ไม่พบ"


13

~ทั้งหมด 4 ไบต์intเท่ากับสูตรนี้-(N+1)

ดังนั้น

~0   = -(0+1)   // -1
~35  = -(35+1)  // -36 
~-35 = -(-35+1) //34 

3
นี้ไม่ได้เป็นจริงเสมอตั้งแต่ ~2147483648 != -(2147483648 + 1)(ตัวอย่าง)
Frxstrem

10

ตัว~ดำเนินการคือตัวดำเนินการเสริมแบบบิต ผลลัพธ์จำนวนเต็มจากinArray()คือ -1 เมื่อไม่พบองค์ประกอบหรือจำนวนเต็มที่ไม่เป็นลบ ส่วนเติมเต็มบิตของ -1 (แสดงเป็นไบนารีเป็น 1 บิตทั้งหมด) เป็นศูนย์ ส่วนเติมเต็มบิตของจำนวนเต็มที่ไม่เป็นลบจะไม่เป็นศูนย์เสมอ

ดังนั้น!!~iจะเกิดขึ้นtrueเมื่อจำนวนเต็ม "i" เป็นจำนวนเต็มไม่เป็นลบและfalseเมื่อ "i" เท่ากับ -1

โปรดทราบว่า~จะบังคับตัวถูกดำเนินการเป็นจำนวนเต็มเสมอ นั่นคือมันบังคับให้ค่าทศนิยมที่ไม่ใช่จำนวนเต็มเป็นจำนวนเต็มเช่นเดียวกับค่าที่ไม่ใช่ตัวเลข


10

Tilde เป็นบิตไม่ - มันจะกลับค่าแต่ละบิต ตามกฎทั่วไปถ้าคุณใช้~กับตัวเลขสัญลักษณ์ของมันจะกลับด้านจากนั้น 1 จะถูกลบออก

ดังนั้นเมื่อคุณทำ~0คุณจะได้ -1 (0 กลับด้านคือ -0 ลบ 1 เป็น -1)

โดยพื้นฐานแล้วเป็นวิธีที่ละเอียดซับซ้อนและได้รับการปรับให้เหมาะสมเป็นพิเศษในการรับค่าที่เป็นบูลีนเสมอ


8

คุณพูดถูก: รหัสนี้จะส่งคืนfalseเมื่อการindexOfโทรกลับ -1; trueมิฉะนั้น

อย่างที่คุณพูดการใช้สิ่งต่างๆเช่น

return this.modifiedPaths.indexOf(path) !== -1;

1
แต่นั่นคืออีก 3 ไบต์ที่จะส่งไปยังลูกค้า! แก้ไข: (แค่ล้อเล่นโพสต์ความคิดเห็นของฉันและตระหนักว่ามันไม่ชัดเจน (ซึ่งทั้งเศร้าและโง่))
Wesley Murch

@ เวสลีย์: นั่นเป็นความจริง แต่จะต้องถูกส่งไปยังลูกค้าแต่ละรายเพียงครั้งเดียวโดยสมมติว่าลูกค้าจะแคชไฟล์.js. ต้องบอกว่าพวกเขาสามารถใช้>=0มากกว่า!==-1- ไม่มีไบต์พิเศษในการส่งและยังอ่านได้ง่ายกว่ารุ่นบิตบิด
LukeH

2
ใครหลอกใครที่นี่? ;) ฉันเดาว่าฉันคิดว่าการเขียนโค้ดที่อ่านได้นั้นดีกว่าโค้ดที่ปรับแต่งไว้ล่วงหน้าแบบคลุมเครือซึ่งสร้างคำถามประเภทนี้ เพียงย่อขนาดในภายหลังและเขียนโค้ดที่อ่านได้และเข้าใจได้ทันที
Wesley Murch

2
โดยส่วนตัวแล้วฉันจะบอกว่า> -1มันอ่านง่ายกว่า แต่นั่นอาจเป็นเรื่องส่วนตัวมาก
โยชิ

6

ตัว~ดำเนินการคือตัวดำเนินการ NOT ในระดับบิต สิ่งนี้หมายความว่าต้องใช้ตัวเลขในรูปแบบไบนารีและเปลี่ยนศูนย์ทั้งหมดให้เป็นเลขและศูนย์ให้เป็นศูนย์

ยกตัวอย่างเช่นจำนวน 0 ในไบนารีคือ0000000ในขณะที่ 11111111-1 ในทำนองเดียวกัน 1 00000001ในไบนารีขณะ -2 11111110คือ


3

ฉันเดาว่ามันอยู่ที่นั่นเพราะมันสั้นกว่าสองสามตัวอักษร (ซึ่งผู้เขียนไลบรารีมักจะตามหลัง) นอกจากนี้ยังใช้การดำเนินการที่ใช้เวลาเพียงไม่กี่รอบเครื่องเมื่อคอมไพล์เป็นรหัสดั้งเดิม (ตรงข้ามกับการเปรียบเทียบกับตัวเลข)

ฉันเห็นด้วยกับคำตอบอื่นว่าเป็นการใช้งานมากเกินไป แต่บางทีอาจสมเหตุสมผลในวงที่รัดกุม (ต้องใช้การประมาณประสิทธิภาพการทำงานมิฉะนั้นอาจเป็นการเพิ่มประสิทธิภาพก่อนเวลาอันควร)


2

ฉันถือว่าเนื่องจากเป็นการดำเนินการในระดับบิตจึงเป็นวิธีที่เร็วที่สุด (ราคาถูกในการคำนวณ) ในการตรวจสอบว่าเส้นทางปรากฏใน modifiedPaths หรือไม่


1

ในฐานะที่เป็น(~(-1)) === 0ดังนั้น:

!!(~(-1)) === Boolean(~(-1)) === Boolean(0) === false

1
อาจถูกต้อง แต่เป็นคำอธิบายที่มีประโยชน์สำหรับผู้ถามหรือไม่? ไม่ใช่เลย. ถ้าฉันไม่เข้าใจในการเริ่มต้นคำตอบสั้น ๆ เช่นนี้จะไม่ช่วย
Spudley

ฉันคิดว่าคำตอบนี้สมเหตุสมผล หากคุณมีสมองด้านคณิตศาสตร์คุณจะเห็นได้ชัดเจนว่าส่วนใดที่เปลี่ยนแปลงไปในแต่ละขั้นตอน เป็นคำตอบที่ดีที่สุดสำหรับคำถามนี้หรือไม่? ไม่ แต่มันมีประโยชน์ฉันคิดอย่างนั้น! +1
Taylor Lopez
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.