ค้นหาเว็บไซต์

javascript - เครื่องหมายทิลด์ทำอะไรเมื่ออยู่หน้าสมการ?


var attr = ~'input,textarea'.indexOf( target.tagName.toLowerCase() )
           ? 'value'
           : 'innerHTML'

ฉันเห็นมันในการตอบหนึ่งครั้ง และฉันไม่เคยเห็นมันมาก่อน

มันหมายความว่าอะไร?

คำตอบ #1

~ เป็นตัวดำเนินการแบบบิตที่สลับบิตทั้งหมดในโอเปอแรนด์ของมัน

ตัวอย่างเช่น ถ้าตัวเลขของคุณคือ 1 การแทนค่าเป็นไบนารีของ IEEE 754 float (ซึ่ง JavaScript ใช้ในการจัดการตัวเลข) จะเป็น...

0011 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

ดังนั้น ~ จะเปลี่ยนตัวดำเนินการของมันให้เป็นจำนวนเต็ม 32 บิต (ตัวดำเนินการแบบบิตใน JavaScript ทำแบบนั้น)...

0000 0000 0000 0000 0000 0000 0000 0001

ถ้ามันเป็นตัวเลขลบ จะถูกจัดเก็บในรูปแบบทวิภาคสอง: พลิกทุกบิตแล้วบวก 1

...แล้วจากนั้นก็กลับค่าทุกบิตของมัน...

1111 1111 1111 1111 1111 1111 1111 1110

แล้วมันมีประโยชน์อะไรล่ะ? แล้วจะมีโอกาสใช้มันเมื่อไหร่กัน?

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

มันยังเป็น เทคนิคที่ (โดยทั่วไป) ไม่ชัดเจนในการเปลี่ยนค่าผลลัพธ์ found ของ indexOf() ให้เป็น ค่า true (ในขณะที่ทำให้ not found เป็น ค่า false) และคนมักใช้มันเพื่อผลข้างเคียงที่ทำให้ตัวเลขถูกตัดเหลือ 32 บิต (และลดทศนิยมโดยการคูณสอง ซึ่งมีผลเหมือนกับ Math.floor() สำหรับตัวเลขบวก)

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

มันก็มีความเกี่ยวข้องน้อยลงในตอนนี้แล้วที่ JavaScript มี Array.prototype.includes() และ String.prototype.includes() ฟังก์ชันเหล่านี้จะคืนค่าประเภทบูลีน ถ้าแพลตฟอร์มเป้าหมายของคุณรองรับ ควรเลือกใช้วิธีนี้สำหรับการทดสอบว่าค่ามีอยู่ในสตริงหรือแอเรย์หรือไม่

คำตอบ #2

การใช้มันก่อนการแสดงออก indexOf() จะให้ผลลัพธ์เป็นค่าจริง/เท็จแทนที่จะเป็นดัชนีเชิงตัวเลขที่ถูกส่งกลับโดยตรง

ถ้าค่าการคืนค่าคือ -1 ดังนั้น ~-1 จะเป็น 0 เพราะ -1 เป็นสตริงของบิตทั้งหมดที่เป็น 1 ค่าที่มากกว่าหรือเท่ากับศูนย์ใด ๆ จะให้ผลลัพธ์ที่ไม่เป็นศูนย์ ดังนั้น,

if (~someString.indexOf(something)) {
}

จะทำให้โค้ด if ทำงานเมื่อ "something" อยู่ใน "someString" หากคุณพยายามใช้ .indexOf() เป็นบูลีนโดยตรง มันจะไม่ทำงานเพราะบางครั้งมันจะคืนค่าเป็นศูนย์ (เมื่อ "something" อยู่ตอนต้นของสตริง)

แน่นอน วิธีนี้ก็ใช้ได้เช่นกัน:

if (someString.indexOf(something) >= 0) {
}

และมันก็น่าพิศวงน้อยลงมาก

บางครั้งคุณก็จะเห็นสิ่งนี้ด้วย:

var i = ~~something;

การใช้ตัวดำเนินการ ~ สองครั้งแบบนั้นเป็นวิธีที่รวดเร็วในการแปลงสตริงเป็นจำนวนเต็ม 32 บิต ~ ตัวแรกทำหน้าที่แปลง และ ~ ตัวที่สองกลับบิตกลับ แน่นอนว่าหากตัวดำเนินการถูกใช้กับสิ่งที่ไม่สามารถแปลงเป็นตัวเลขได้ คุณจะได้ผลลัพธ์เป็น NaN (แก้ไข — จริง ๆ แล้ว ~ ตัวที่สองถูกนำไปใช้ก่อน แต่คุณก็เข้าใจแนวคิด)

คำตอบ #3

เครื่องหมาย ~ คือ ตัวดำเนินการ NOT แบบบิต, ~x ประมาณว่าเหมือนกับ -(x+1) มันเข้าใจง่ายขึ้น แบบหนึ่ง ดังนั้น:

~2;    // -(2+1) ==> -3

พิจารณา -(x+1) -1 สามารถทำการดำเนินการนั้นเพื่อให้ได้ 0

ในคำอื่น ๆ, ~ ที่ใช้กับช่วงของค่าตัวเลขจะให้ค่าที่เป็นเท็จ (ถูกบังคับให้เป็น false จาก 0) เฉพาะสำหรับค่าข้อมูลนำเข้า -1 เท่านั้น มิฉะนั้น จะเป็นค่าความจริงอื่น ๆ

ตามที่เราทราบกันดี -1 มักถูกเรียกว่า sentinel value ค่าดังกล่าวถูกใช้ในหลายฟังก์ชันที่คืนค่า >= 0 สำหรับ ความสำเร็จ และ -1 สำหรับ ความล้มเหลว ในภาษา C ซึ่งเป็นกฎเดียวกันกับค่าที่คืนจาก indexOf() ใน JavaScript

เป็นเรื่องปกติที่จะตรวจสอบว่ามีหรือไม่มีสตริงย่อยในสตริงอื่นด้วยวิธีนี้

var a = "Hello Baby";

if (a.indexOf("Ba") >= 0) {
    // found it
}
if (a.indexOf("Ba") != -1) { 
    // found it
}

if (a.indexOf("aB") < 0) { 
    // not found
}
if (a.indexOf( "aB" ) == -1) { 
    // not found
}

อย่างไรก็ตาม จะง่ายกว่าถ้าทำผ่าน ~ ดังด้านล่าง

var a = "Hello Baby";

~a.indexOf("Ba");         // -7   -> truthy
if (~a.indexOf("Ba")) {   // true
    // found it
}

~a.indexOf("aB");         // 0    -> falsy
!~a.indexOf("aB");        // true
if (!~a.indexOf( "aB" )) {  // true
    // not found
}

คุณไม่รู้จัก JS: ประเภทและไวยากรณ์ โดย ไคล์ ซิมป์สัน

คำตอบ #4

~indexOf(item) มาบ่อยมาก และคำตอบที่นี่ก็ดี แต่บางทีบางคนอาจแค่ต้องการรู้วิธีใช้มันและ "ข้าม" ทฤษฎีไป:

   if (~list.indexOf(item)) {
     // item in list
   } else {
     // item *not* in list
   }

คำตอบ #5

สำหรับผู้ที่กำลังพิจารณาใช้เทคนิค tilde เพื่อสร้างค่า truthy จากผลลัพธ์ของ indexOf การใช้วิธี includes บน String จะชัดเจนกว่าและมีความลึกลับน้อยกว่า

'hello world'.includes('hello') //=> true
'hello world'.includes('kittens') //=> false

โปรดทราบว่านี่เป็นวิธีมาตรฐานใหม่ตั้งแต่ ES 2015 ดังนั้นมันจะไม่ทำงานบนเบราว์เซอร์รุ่นเก่า ในกรณีที่เรื่องนี้สำคัญ ควรพิจารณาใช้ polyfill ของ String.prototype.includes

ฟีเจอร์นี้ยังสามารถใช้กับอาเรย์โดยใช้ไวยากรณ์เดียวกันได้:

['apples', 'oranges', 'cherries'].includes('apples') //=> true
['apples', 'oranges', 'cherries'].includes('unicorns') //=> false

นี่คือ polyfill ของ Array.prototype.includes หากคุณต้องการรองรับเบราว์เซอร์รุ่นเก่า

บทความที่เกี่ยวข้อง