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 หากคุณต้องการรองรับเบราว์เซอร์รุ่นเก่า
