Array.prototype.includes เทียบกับ Array.prototype.indexOf


115

นอกเหนือจากการอ่านที่ดีขึ้นจะมีประโยชน์ใด ๆ ที่includesมากกว่าindexOf? พวกเขาดูเหมือนกับฉัน

อะไรคือความแตกต่างระหว่างสิ่งนี้

var x = [1,2,3].indexOf(1) > -1; //true

และนี่?

var y = [1,2,3].includes(1); //true

13
includesมีการรองรับเบราว์เซอร์ที่แย่กว่ามาก
Quentin

4
โปรดทราบว่าincludesไม่ใช่ส่วนหนึ่งของ ES6 / ES2015 เป็นข้อเสนอสำหรับ ECMAScript เวอร์ชันถัดไปและจะเพิ่มในปีนี้
Felix Kling

4
แค่อยากจะพูดถึงที่includesไม่รองรับใน IE เลย
ZvKa

คำตอบ:


141

tl; dr: NaNได้รับการปฏิบัติที่แตกต่างกัน:

  • [NaN].indexOf(NaN) > -1 คือ false
  • [NaN].includes(NaN) คือ true

จากข้อเสนอ :

แรงจูงใจ

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

if (arr.indexOf(el) !== -1) {
    ...
}

มีความเป็นไปได้อื่น ๆ อีกมากมายเช่นหรือแม้กระทั่งarr.indexOf(el) >= 0~arr.indexOf(el)

รูปแบบเหล่านี้แสดงปัญหาสองประการ:

  • พวกเขาไม่ "พูดในสิ่งที่คุณหมายถึง": แทนที่จะถามว่าอาร์เรย์มีองค์ประกอบหรือไม่คุณถามว่าดัชนีของการเกิดขึ้นครั้งแรกขององค์ประกอบนั้นในอาร์เรย์คืออะไรจากนั้นจึงเปรียบเทียบหรือบิดบิตเพื่อพิจารณา คำตอบสำหรับคำถามที่แท้จริงของคุณ
  • พวกเขาล้มเหลวNaNเนื่องจากindexOfใช้การเปรียบเทียบความเท่าเทียมกันอย่างเข้มงวดและด้วยเหตุ[NaN].indexOf(NaN) === -1นี้

โซลูชันที่เสนอ

เราขอเสนอวิธีการเพิ่มเติมArray.prototype.includesเพื่อให้รูปแบบข้างต้นสามารถเขียนใหม่ได้

if (arr.includes(el)) {
    ...
}

สิ่งนี้มีความหมายเกือบจะเหมือนกับข้างต้นยกเว้นว่าจะใช้อัลกอริธึมการเปรียบเทียบ SameValueZero แทนการเปรียบเทียบความเสมอภาคอย่างเข้มงวดจึงทำให้[NaN].includes(NaN)เป็นจริง

ดังนั้นข้อเสนอนี้จะช่วยแก้ปัญหาทั้งสองอย่างที่พบในโค้ดที่มีอยู่

นอกจากนี้เรายังเพิ่มfromIndexพารามิเตอร์ที่คล้ายกับArray.prototype.indexOfและString.prototype.includesเพื่อความสอดคล้อง


ข้อมูลเพิ่มเติม:


1
ความจริงเพียงครึ่งเดียว. นอกจากนี้ยังแตกต่างกัน: องค์ประกอบที่ขาดหายไปจะถือว่าเป็นundefinedโดยและไม่ได้รับการพิจารณาโดย.includes() .indexOf()
Robert Siemer

12

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

IMHO ฉันชอบเขียนif (arr.includes(el)) {}เนื่องจากมีความชัดเจนและสามารถบำรุงรักษาได้มากกว่าif (arr.indexOf(el) !== -1) {}


1
ดูเหมือนว่าความแตกต่างของประสิทธิภาพจะไม่ชัดเจนนัก Firefox บนมือถือของฉันแสดงให้เห็นว่า indexOf เร็วขึ้นจริง Chrome บางเวอร์ชันทำหน้าที่เหมือนกัน ... แต่ความแตกต่างก็ดูเหมือนเล็กน้อยในการใช้งานในปัจจุบัน
Nux

8

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

การใช้งานใน Array

( ลิงก์ไปยังข้อกำหนด ECMAScript)

  1. indexOfใช้การเปรียบเทียบความเท่าเทียมกันอย่างเข้มงวดในขณะที่includesใช้อัลกอริทึมSameValueZero ด้วยเหตุนี้ความแตกต่างสองประการต่อไปนี้จึงเกิดขึ้น

  2. ในฐานะที่เป็นแหลมออกโดยเฟลิกซ์แพรวNaNพฤติกรรมที่แตกต่างกันในกรณีของ

let arr = [NaN];

arr.indexOf(NaN); // returns -1; meaning NaN is not present
arr.includes(NaN); // returns true
  1. undefinedพฤติกรรมยังแตกต่างกันในกรณีของ
let arr = [ , , ];

arr.indexOf(undefined); // returns -1; meaning undefined is not present
arr.includes(undefined); // returns true

การใช้งานใน String

( ลิงก์ไปยังข้อกำหนด ECMAScript)

  1. หากคุณส่ง RegExp ไปยัง RegExp indexOfจะถือว่า RegExp เป็นสตริงและจะส่งคืนดัชนีของสตริงหากพบ อย่างไรก็ตามหากคุณส่ง RegExp ไปincludesก็จะทำให้เกิดข้อยกเว้น
let str = "javascript";

str.indexOf(/\w/); // returns -1 even though the elements match the regex because /\w/ is treated as string
str.includes(/\w/); // throws TypeError: First argument to String.prototype.includes must not be a regular expression

ประสิทธิภาพ

ดังที่538ROMEOชี้ให้เห็นincludesอาจช้าลงเล็กน้อย (เล็กมาก) เล็กน้อย (เนื่องจากจำเป็นต้องตรวจสอบ regex เป็นอาร์กิวเมนต์แรก) มากกว่าindexOfแต่ในความเป็นจริงสิ่งนี้ไม่ได้สร้างความแตกต่างมากนักและไม่มีความสำคัญ

ประวัติศาสตร์

String.prototype.includes()ได้รับการแนะนำใน ECMAScript 2015 ในขณะที่Array.prototype.includes()เปิดตัวใน ECMAScript 2016 สำหรับการสนับสนุนเบราว์เซอร์ให้ใช้อย่างชาญฉลาด

String.prototype.indexOf()และArray.prototype.indexOf()มีอยู่ใน ECMAScript รุ่น ES5 และด้วยเหตุนี้จึงสนับสนุนโดยเบราว์เซอร์ทั้งหมด


indexOfให้trueหลังจากตั้งค่าอย่างชัดเจนundefinedในอาร์เรย์: let arr=[undefined];หรือlet arr=[];arr[0]=undefined;ตอนนี้arr.indexOf(undefined) === 0
Jay Dadhania

คุณเป็นคนเดียวที่ระบุความแตกต่างด้วยundefinedเหตุผลก็คือ.includesถือว่าองค์ประกอบที่ขาดหายไปในundefinedขณะที่.indexOf()ไม่สนใจองค์ประกอบเหล่านั้น นอกจากนี้คุณยังสามารถ“สร้าง” arr[number beyond length] = whateverองค์ประกอบที่ขาดหายไปด้วย
Robert Siemer

ไม่มีใครขอสาย แต่คำพูดของคุณแนะนำให้.includes()กินเฉพาะสาย ในความเป็นจริงทั้งสองวิธีบังคับให้สตริงใด ๆ ดีที่สุดเท่าที่จะทำได้ Regex ได้รับการยกเว้นเฉพาะเป็นอาร์กิวเมนต์.includes()ที่จะอนุญาตให้มีการเพิ่มเติมในอนาคตให้ได้มาตรฐานตามที่ร่างปัจจุบัน
Robert Siemer

4

ตามแนวคิดคุณควรใช้ indexOf เมื่อคุณต้องการใช้ตำแหน่ง indexOf เพียงแค่ให้คุณแยกค่าหรือดำเนินการกับอาร์เรย์เช่นใช้ slice, shift หรือ split หลังจากที่คุณได้ตำแหน่งขององค์ประกอบ ในทางกลับกัน Use Array.inc รวมเฉพาะเพื่อให้ทราบว่าค่านั้นอยู่ในอาร์เรย์หรือไม่และไม่ใช่ตำแหน่งเพราะคุณไม่สนใจมัน


0

indexOf()และincludes()สามารถใช้ทั้งสองอย่างเพื่อค้นหาองค์ประกอบในอาร์เรย์อย่างไรก็ตามแต่ละฟังก์ชันจะให้ค่าตอบแทนที่แตกต่างกัน

indexOfส่งคืนตัวเลข ( -1หากองค์ประกอบไม่มีอยู่ในอาร์เรย์หรือตำแหน่งอาร์เรย์หากมีองค์ประกอบอยู่)

includes()ส่งคืนค่าบูลีน ( trueหรือfalse)


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