ออบเจ็กต์ช่วยให้คุณสามารถจัดเก็บคอลเลกชันค่าที่คีย์ไว้ได้ ไม่เป็นไร.
แต่บ่อยครั้งที่เราพบว่าเราต้องการ คอลเลกชันที่เรียงลำดับ โดยที่เรามีองค์ประกอบที่ 1, 2, 3 และต่อๆ ไป ตัวอย่างเช่น เราจำเป็นต้องจัดเก็บรายการบางอย่าง เช่น ผู้ใช้ สินค้า องค์ประกอบ HTML เป็นต้น
ไม่สะดวกที่จะใช้วัตถุที่นี่ เนื่องจากไม่มีวิธีในการจัดการลำดับขององค์ประกอบ เราไม่สามารถแทรกคุณสมบัติใหม่ "ระหว่าง" คุณสมบัติที่มีอยู่ได้ วัตถุไม่ได้มีไว้สำหรับการใช้งานดังกล่าว
มีโครงสร้างข้อมูลพิเศษชื่อ Array
เพื่อจัดเก็บคอลเลกชันที่เรียงลำดับ
มีสองไวยากรณ์สำหรับการสร้างอาร์เรย์ว่าง:
ให้ arr = อาร์เรย์ใหม่ (); ให้ arr = [];
มักใช้ไวยากรณ์ที่สองเกือบตลอดเวลา เราสามารถใส่องค์ประกอบเริ่มต้นในวงเล็บได้:
ให้ผลไม้ = ["แอปเปิ้ล", "ส้ม", "พลัม"];
องค์ประกอบอาร์เรย์จะถูกกำหนดหมายเลข โดยเริ่มจากศูนย์
เราสามารถรับองค์ประกอบตามหมายเลขในวงเล็บเหลี่ยม:
ให้ผลไม้ = ["แอปเปิ้ล", "ส้ม", "พลัม"]; การแจ้งเตือน ( ผลไม้[0] ); // แอปเปิล การแจ้งเตือน ( ผลไม้[1] ); // ส้ม การแจ้งเตือน ( ผลไม้[2] ); //พลัม
เราสามารถแทนที่องค์ประกอบได้:
ผลไม้[2] = 'ลูกแพร์'; // ตอนนี้ ["แอปเปิ้ล", "ส้ม", "ลูกแพร์"]
…หรือเพิ่มอันใหม่ให้กับอาเรย์:
ผลไม้[3] = 'มะนาว'; // ตอนนี้ ["แอปเปิ้ล", "ส้ม", "ลูกแพร์", "มะนาว"]
จำนวนองค์ประกอบทั้งหมดในอาร์เรย์คือ length
:
ให้ผลไม้ = ["แอปเปิ้ล", "ส้ม", "พลัม"]; การแจ้งเตือน (ผลไม้ความยาว); // 3
นอกจากนี้เรายังสามารถใช้ alert
เพื่อแสดงอาร์เรย์ทั้งหมดได้
ให้ผลไม้ = ["แอปเปิ้ล", "ส้ม", "พลัม"]; การแจ้งเตือน ( ผลไม้ ); // แอปเปิ้ล,ส้ม,พลัม
อาร์เรย์สามารถจัดเก็บองค์ประกอบประเภทใดก็ได้
ตัวอย่างเช่น:
// การผสมผสานของค่า ให้ arr = [ 'Apple', { ชื่อ: 'John' }, true, function() { alert('hello'); - // รับวัตถุที่ดัชนี 1 แล้วแสดงชื่อของมัน การแจ้งเตือน( arr[1].ชื่อ ); // จอห์น // รับฟังก์ชันที่ดัชนี 3 แล้วรัน ถึง[3](); // สวัสดี
เครื่องหมายจุลภาคต่อท้าย
อาร์เรย์ เช่นเดียวกับวัตถุ อาจลงท้ายด้วยลูกน้ำ:
ให้ผลไม้ = [ "แอปเปิล", "ส้ม", "พลัม" -
รูปแบบ “เครื่องหมายจุลภาคต่อท้าย” ช่วยให้แทรกหรือลบรายการได้ง่ายขึ้น เนื่องจากทุกบรรทัดจะเหมือนกัน
นอกจากนี้ล่าสุด
นี่เป็นส่วนเพิ่มเติมล่าสุดของภาษา เบราว์เซอร์รุ่นเก่าอาจต้องใช้โพลีฟิล
สมมติว่าเราต้องการองค์ประกอบสุดท้ายของอาร์เรย์
ภาษาโปรแกรมบางภาษาอนุญาตให้ใช้ดัชนีเชิงลบเพื่อจุดประสงค์เดียวกัน เช่น fruits[-1]
แม้ว่าใน JavaScript มันจะไม่ทำงาน ผลลัพธ์จะ undefined
เนื่องจากดัชนีในวงเล็บเหลี่ยมจะถือเป็นค่าตามตัวอักษร
เราสามารถคำนวณดัชนีองค์ประกอบสุดท้ายอย่างชัดเจนแล้วเข้าถึงได้: fruits[fruits.length - 1]
ให้ผลไม้ = ["แอปเปิ้ล", "ส้ม", "พลัม"]; การแจ้งเตือน( ผลไม้[fruits.length-1] ); //พลัม
ยุ่งยากนิดหน่อยใช่ไหม? เราต้องเขียนชื่อตัวแปรสองครั้ง
โชคดีที่มีไวยากรณ์ที่สั้นกว่า: fruits.at(-1)
:
ให้ผลไม้ = ["แอปเปิ้ล", "ส้ม", "พลัม"]; // เช่นเดียวกับผลไม้[fruits.length-1] การแจ้งเตือน (fruits.at(-1) ); //พลัม
กล่าวอีกนัยหนึ่ง arr.at(i)
:
เหมือนกันทุกประการ arr[i]
ถ้า i >= 0
สำหรับค่าลบของ i
มันจะถอยกลับจากจุดสิ้นสุดของอาร์เรย์
คิวเป็นหนึ่งในการใช้อาเรย์ที่พบบ่อยที่สุด ในวิทยาการคอมพิวเตอร์ หมายถึงการรวบรวมองค์ประกอบตามลำดับซึ่งสนับสนุนการดำเนินการสองประการ:
push
จะเพิ่มองค์ประกอบต่อท้าย
shift
รับองค์ประกอบจากจุดเริ่มต้น เลื่อนคิว เพื่อให้องค์ประกอบที่ 2 กลายเป็นองค์ประกอบที่ 1
อาร์เรย์รองรับการดำเนินการทั้งสอง
ในทางปฏิบัติเราต้องการมันบ่อยมาก เช่น คิวข้อความที่ต้องแสดงบนหน้าจอ
มีกรณีการใช้งานอื่นสำหรับอาร์เรย์ – โครงสร้างข้อมูลชื่อสแต็ก
รองรับสองการดำเนินการ:
push
เพิ่มองค์ประกอบที่ส่วนท้าย
pop
ปรับองค์ประกอบจากจุดสิ้นสุด
องค์ประกอบใหม่จึงถูกเพิ่มหรือนำมาจาก "จุดสิ้นสุด" เสมอ
โดยปกติแล้ว กองจะแสดงเป็นชุดไพ่ โดยจะมีการเพิ่มไพ่ใหม่ไว้ด้านบนหรือนำมาจากด้านบน:
สำหรับสแต็ก รายการที่ถูกพุชล่าสุดจะได้รับก่อน ซึ่งเรียกอีกอย่างว่าหลักการ LIFO (เข้าก่อน-ออกก่อน) สำหรับคิวเรามี FIFO (เข้าก่อน-ออกก่อน)
อาร์เรย์ใน JavaScript สามารถทำงานได้ทั้งแบบคิวและแบบสแต็ก อนุญาตให้คุณเพิ่ม/ลบองค์ประกอบ ทั้งไปยัง/จากจุดเริ่มต้นหรือจุดสิ้นสุด
ในวิทยาการคอมพิวเตอร์ โครงสร้างข้อมูลที่เอื้ออำนวยสิ่งนี้เรียกว่า deque
วิธีการทำงานกับจุดสิ้นสุดของอาร์เรย์:
pop
แยกองค์ประกอบสุดท้ายของอาร์เรย์และส่งกลับ:
ให้ผลไม้ = ["แอปเปิ้ล", "ส้ม", "ลูกแพร์"]; การแจ้งเตือน(fruits.pop() ); // เอา "แพร์" ออกแล้วแจ้งเตือน การแจ้งเตือน ( ผลไม้ ); // แอปเปิ้ล, ส้ม
ทั้ง fruits.pop()
และ fruits.at(-1)
ส่งคืนองค์ประกอบสุดท้ายของอาร์เรย์ แต่ fruits.pop()
ยังแก้ไขอาร์เรย์ด้วยการลบออก
push
ผนวกองค์ประกอบที่ส่วนท้ายของอาร์เรย์:
ให้ผลไม้ = ["Apple", "Orange"]; Fruits.push("ลูกแพร์"); การแจ้งเตือน ( ผลไม้ ); // แอปเปิ้ล, ส้ม, แพร์
การโทร fruits.push(...)
เท่ากับ fruits[fruits.length] = ...
วิธีการทำงานกับจุดเริ่มต้นของอาร์เรย์:
shift
แยกองค์ประกอบแรกของอาร์เรย์และส่งกลับ:
ให้ผลไม้ = ["แอปเปิ้ล", "ส้ม", "ลูกแพร์"]; การแจ้งเตือน(fruits.shift() ); // ลบ Apple และแจ้งเตือน การแจ้งเตือน ( ผลไม้ ); // ส้ม,แพร์
unshift
เพิ่มองค์ประกอบที่จุดเริ่มต้นของอาร์เรย์:
ให้ผลไม้ = ["ส้ม", "ลูกแพร์"]; ผลไม้.unshift('แอปเปิ้ล'); การแจ้งเตือน ( ผลไม้ ); // แอปเปิ้ล, ส้ม, แพร์
วิธี push
และ unshift
สามารถเพิ่มองค์ประกอบหลายรายการพร้อมกัน:
ให้ผลไม้ = ["แอปเปิ้ล"]; Fruits.push("ส้ม", "พีช"); Fruits.unshift("สับปะรด", "มะนาว"); // ["สับปะรด", "มะนาว", "แอปเปิ้ล", "ส้ม", "พีช"] การแจ้งเตือน ( ผลไม้ );
อาร์เรย์เป็นวัตถุชนิดพิเศษ วงเล็บเหลี่ยมที่ใช้ในการเข้าถึงคุณสมบัติ arr[0]
จริงๆ แล้วมาจากไวยากรณ์ของวัตถุ โดยพื้นฐานแล้วเหมือนกับ obj[key]
โดยที่ arr
เป็นวัตถุในขณะที่ตัวเลขถูกใช้เป็นกุญแจ
พวกเขาขยายออบเจ็กต์ที่มีวิธีการพิเศษในการทำงานกับการรวบรวมข้อมูลที่ได้รับคำสั่งและคุณสมบัติ length
แต่ที่แกนกลางมันยังคงเป็นวัตถุ
โปรดจำไว้ว่า JavaScript มีประเภทข้อมูลพื้นฐานเพียงแปดประเภทเท่านั้น (ดูบทประเภทข้อมูลสำหรับข้อมูลเพิ่มเติม) อาร์เรย์เป็นวัตถุและมีพฤติกรรมเหมือนวัตถุ
ตัวอย่างเช่น มันถูกคัดลอกโดยการอ้างอิง:
ให้ผลไม้ = ["กล้วย"] ให้ arr = ผลไม้; // คัดลอกโดยการอ้างอิง (ตัวแปรสองตัวอ้างอิงอาร์เรย์เดียวกัน) alert( arr === ผลไม้ ); // จริง arr.push("ลูกแพร์"); // แก้ไขอาร์เรย์โดยการอ้างอิง การแจ้งเตือน ( ผลไม้ ); // กล้วย ลูกแพร์ - 2 รายการแล้ว
…แต่สิ่งที่ทำให้อาร์เรย์มีความพิเศษจริงๆ คือการเป็นตัวแทนภายในของอาร์เรย์ เอ็นจิ้นพยายามจัดเก็บองค์ประกอบต่างๆ ไว้ในพื้นที่หน่วยความจำที่อยู่ติดกัน ทีละชิ้นๆ ดังที่ปรากฎในภาพประกอบในบทนี้ และยังมีการปรับปรุงอื่นๆ ด้วยเช่นกัน เพื่อทำให้อาร์เรย์ทำงานได้เร็วมาก
แต่พวกมันทั้งหมดพังถ้าเราเลิกทำงานกับอาร์เรย์เหมือนกับ "คอลเลกชันที่ได้รับคำสั่ง" และเริ่มทำงานกับมันราวกับว่ามันเป็นวัตถุปกติ
ตัวอย่างเช่น ในทางเทคนิคแล้ว เราสามารถทำได้:
ให้ผลไม้ = []; // สร้างอาร์เรย์ ผลไม้[99999] = 5; // กำหนดคุณสมบัติที่มีดัชนีมากกว่าความยาวของมันมาก ผลไม้อายุ = 25; // สร้างคุณสมบัติด้วยชื่อที่กำหนดเอง
นั่นเป็นไปได้ เนื่องจากอาร์เรย์เป็นวัตถุที่ฐานของมัน เราสามารถเพิ่มคุณสมบัติใดๆ ลงไปได้
แต่เอ็นจิ้นจะเห็นว่าเรากำลังทำงานกับอาร์เรย์เหมือนกับวัตถุทั่วไป การเพิ่มประสิทธิภาพเฉพาะอาร์เรย์ไม่เหมาะกับกรณีดังกล่าว และจะถูกปิด ประโยชน์ที่ได้รับจะหายไป
วิธีใช้อาร์เรย์ในทางที่ผิด:
เพิ่มคุณสมบัติที่ไม่ใช่ตัวเลข เช่น arr.test = 5
ทำรูเช่น: เพิ่ม arr[0]
แล้ว arr[1000]
(และไม่มีอะไรอยู่ระหว่างนั้น)
เติมอาร์เรย์ในลำดับย้อนกลับ เช่น arr[1000]
, arr[999]
และอื่นๆ
โปรดคิดว่าอาร์เรย์เป็นโครงสร้างพิเศษที่จะทำงานกับ ข้อมูลที่เรียงลำดับ พวกเขามีวิธีการพิเศษสำหรับสิ่งนั้น อาร์เรย์ได้รับการปรับแต่งอย่างระมัดระวังภายในกลไก JavaScript เพื่อให้ทำงานกับข้อมูลที่เรียงลำดับต่อเนื่องกัน โปรดใช้วิธีนี้ และหากคุณต้องการคีย์ที่กำหนดเอง มีโอกาสสูงที่คุณจะต้องใช้ออบเจ็กต์ปกติ {}
เมธอด push/pop
ทำงานเร็ว ในขณะที่ shift/unshift
ทำงานช้า
เหตุใดการทำงานกับจุดสิ้นสุดของอาร์เรย์จึงเร็วกว่าการทำงานกับจุดเริ่มต้น มาดูกันว่าเกิดอะไรขึ้นระหว่างการดำเนินการ:
ผลไม้.กะ(); // รับ 1 องค์ประกอบตั้งแต่เริ่มต้น
การนำและลบองค์ประกอบที่มีดัชนี 0
ไม่เพียงพอ องค์ประกอบอื่นๆ จำเป็นต้องได้รับการกำหนดหมายเลขใหม่เช่นกัน
การดำเนิน shift
ต้องทำ 3 สิ่ง:
ลบองค์ประกอบที่มีดัชนี 0
ย้ายองค์ประกอบทั้งหมดไปทางซ้าย กำหนดหมายเลขใหม่จากดัชนี 1
ถึง 0
จาก 2
เป็น 1
และต่อๆ ไป
อัพเดตคุณสมบัติ length
ยิ่งมีองค์ประกอบในอาร์เรย์มากเท่าใด เวลาในการย้ายก็จะยิ่งมากขึ้น การดำเนินการในหน่วยความจำก็จะมากขึ้นเท่านั้น
สิ่งที่คล้ายกันนี้เกิดขึ้นกับ unshift
: ในการเพิ่มองค์ประกอบที่จุดเริ่มต้นของอาร์เรย์ เราต้องย้ายองค์ประกอบที่มีอยู่ไปทางขวาก่อน เพื่อเพิ่มดัชนี
แล้ว push/pop
ล่ะ? พวกเขาไม่จำเป็นต้องย้ายอะไร หากต้องการแยกองค์ประกอบออกจากส่วนท้าย วิธี pop
จะล้างดัชนีและลด length
ให้สั้นลง
การดำเนินการสำหรับการดำเนินการ pop
:
ผลไม้.ป๊อป(); // รับ 1 องค์ประกอบจากจุดสิ้นสุด
วิธี pop
ไม่จำเป็นต้องย้ายสิ่งใด เนื่องจากองค์ประกอบอื่นๆ จะเก็บดัชนีไว้ นั่นเป็นเหตุผลว่าทำไมมันถึงเร็วมาก
สิ่งที่คล้ายกันกับวิธี push
หนึ่งในวิธีที่เก่าแก่ที่สุดในการวนรอบรายการอาร์เรย์คือ for
loop over indexes:
ให้ arr = ["Apple", "Orange", "Pear"]; สำหรับ (ให้ i = 0; i < arr.length; i++) { การแจ้งเตือน( arr[i] ); -
แต่สำหรับอาร์เรย์จะมีการวนซ้ำอีกรูปแบบหนึ่ง for..of
:
ให้ผลไม้ = ["แอปเปิ้ล", "ส้ม", "พลัม"]; // วนซ้ำองค์ประกอบอาร์เรย์ สำหรับ (ให้ผลไม้ของผลไม้) { การแจ้งเตือน ( ผลไม้ ); -
for..of
ไม่ได้ให้สิทธิ์เข้าถึงจำนวนขององค์ประกอบปัจจุบัน เพียงแค่ค่าของมัน แต่ในกรณีส่วนใหญ่ก็เพียงพอแล้ว และมันสั้นกว่า
ในทางเทคนิคแล้ว เนื่องจากอาร์เรย์เป็นวัตถุ จึงเป็นไปได้ที่จะใช้ for..in
:
ให้ arr = ["Apple", "Orange", "Pear"]; สำหรับ (ให้ป้อน arr) { การแจ้งเตือน( arr[คีย์] ); // แอปเปิ้ล, ส้ม, แพร์ -
แต่นั่นเป็นความคิดที่ไม่ดีจริงๆ อาจมีปัญหาเกิดขึ้น:
การวนซ้ำ for..in
วนซ้ำ คุณสมบัติทั้งหมด ไม่ใช่แค่ตัวเลขเท่านั้น
มีสิ่งที่เรียกว่า "คล้ายอาร์เรย์" ในเบราว์เซอร์และในสภาพแวดล้อมอื่นๆ ที่ ดูเหมือนอาร์เรย์ นั่นคือมีคุณสมบัติ length
และดัชนี แต่อาจมีคุณสมบัติและวิธีการอื่นๆ ที่ไม่ใช่ตัวเลขด้วย ซึ่งโดยปกติเราไม่ต้องการ for..in
วนซ้ำจะแสดงรายการเหล่านั้น ดังนั้นหากเราจำเป็นต้องทำงานกับออบเจ็กต์ที่มีลักษณะคล้ายอาเรย์ คุณสมบัติ "พิเศษ" เหล่านี้ก็อาจกลายเป็นปัญหาได้
for..in
loop ได้รับการปรับให้เหมาะสมสำหรับอ็อบเจ็กต์ทั่วไป ไม่ใช่อาร์เรย์ และทำให้ช้าลง 10-100 เท่า แน่นอนว่ามันยังเร็วมาก การเร่งความเร็วอาจมีความสำคัญเฉพาะในคอขวดเท่านั้น แต่เราก็ยังควรตระหนักถึงความแตกต่าง
โดยทั่วไปเราไม่ควรใช้ for..in
สำหรับอาร์เรย์
คุณสมบัติ length
จะอัปเดตโดยอัตโนมัติเมื่อเราแก้ไขอาร์เรย์ ถ้าให้แม่นยำ จริงๆ แล้วมันไม่ใช่การนับค่าในอาร์เรย์ แต่เป็นดัชนีตัวเลขที่ยิ่งใหญ่ที่สุดบวกหนึ่ง
ตัวอย่างเช่น องค์ประกอบเดียวที่มีดัชนีขนาดใหญ่จะให้ความยาวมาก:
ให้ผลไม้ = []; ผลไม้[123] = "แอปเปิ้ล"; การแจ้งเตือน (ผลไม้ความยาว); // 124
โปรดทราบว่าโดยปกติแล้วเราจะไม่ใช้อาร์เรย์เช่นนั้น
สิ่งที่น่าสนใจอีกอย่างเกี่ยวกับคุณสมบัติ length
ก็คือมันสามารถเขียนได้
ถ้าเราเพิ่มมันด้วยตนเอง จะไม่มีอะไรน่าสนใจเกิดขึ้น แต่ถ้าเราลดมันลง อาเรย์ก็จะถูกตัดทอนลง กระบวนการนี้ไม่สามารถย้อนกลับได้ ต่อไปนี้คือตัวอย่าง:
ให้ arr = [1, 2, 3, 4, 5]; arr.ความยาว = 2; // ตัดทอนเหลือ 2 องค์ประกอบ แจ้งเตือน(arr); // [1, 2] arr.ความยาว = 5; //ส่งคืนความยาวกลับ การแจ้งเตือน (arr[3] ); // ไม่ได้กำหนด: ค่าจะไม่ส่งคืน
ดังนั้น วิธีที่ง่ายที่สุดในการล้างอาเรย์คือ: arr.length = 0;
-
มีอีกหนึ่งไวยากรณ์สำหรับสร้างอาร์เรย์:
ให้ arr = อาร์เรย์ใหม่ ("Apple", "Pear", "etc");
ไม่ค่อยได้ใช้ เนื่องจากวงเล็บเหลี่ยม []
จะสั้นกว่า นอกจากนี้ยังมีคุณสมบัติที่ยุ่งยากด้วย
หากมีการเรียก new Array
ด้วยอาร์กิวเมนต์เดียวซึ่งเป็นตัวเลข มันจะสร้างอาร์เรย์ โดยไม่มีรายการ แต่มีความยาวที่กำหนด
มาดูกันว่าเราจะยิงตัวเองเข้าที่เท้าได้อย่างไร:
ให้ arr = อาร์เรย์ใหม่ (2); // มันจะสร้างอาร์เรย์เป็น [2] หรือไม่? การแจ้งเตือน (arr[0] ); // ไม่ได้กำหนด! ไม่มีองค์ประกอบ การแจ้งเตือน( arr.length ); // ความยาว 2
เพื่อหลีกเลี่ยงเหตุการณ์ไม่คาดคิด เรามักจะใช้วงเล็บเหลี่ยม เว้นแต่เราจะรู้จริงๆ ว่ากำลังทำอะไรอยู่
อาร์เรย์สามารถมีรายการที่เป็นอาร์เรย์ได้เช่นกัน เราสามารถใช้มันกับอาร์เรย์หลายมิติ เช่น เพื่อจัดเก็บเมทริกซ์:
ให้เมทริกซ์ = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] - การแจ้งเตือน (เมทริกซ์[0][1] ); // 2 ค่าที่สองของอาร์เรย์ภายในตัวแรก
อาร์เรย์มีการใช้เมธอด toString
ของตัวเองซึ่งส่งคืนรายการองค์ประกอบที่คั่นด้วยเครื่องหมายจุลภาค
ตัวอย่างเช่น:
ให้ arr = [1, 2, 3]; แจ้งเตือน(arr); // 1,2,3 การแจ้งเตือน( สตริง(arr) === '1,2,3' ); // จริง
เรามาลองสิ่งนี้กัน:
การแจ้งเตือน ( [] + 1 ); // "1" การแจ้งเตือน ( [1] + 1 ); // "11" การแจ้งเตือน ( [1,2] + 1 ); // "1,21"
อาร์เรย์ไม่มี Symbol.toPrimitive
ทั้ง valueOf
ที่ทำงานได้ พวกมันใช้เฉพาะการแปลง toString
ดังนั้นที่นี่ []
กลายเป็นสตริงว่าง [1]
กลายเป็น "1"
และ [1,2]
กลายเป็น "1,2"
เมื่อตัวดำเนินการไบนารีบวก "+"
เพิ่มบางสิ่งลงในสตริง มันจะแปลงเป็นสตริงด้วย ดังนั้นขั้นตอนต่อไปจะมีลักษณะดังนี้:
การแจ้งเตือน( "" + 1 ); // "1" การแจ้งเตือน ( "1" + 1 ); // "11" การแจ้งเตือน ( "1,2" + 1 ); // "1,21"
ไม่ควรเปรียบเทียบอาร์เรย์ใน JavaScript ซึ่งต่างจากภาษาการเขียนโปรแกรมอื่นๆ กับตัวดำเนินการ ==
โอเปอเรเตอร์นี้ไม่มีการดูแลเป็นพิเศษสำหรับอาร์เรย์ แต่จะทำงานร่วมกับอาร์เรย์ได้เช่นเดียวกับอ็อบเจ็กต์อื่นๆ
มาจำกฎกัน:
วัตถุสองชิ้นมีค่าเท่ากัน ==
เฉพาะในกรณีที่วัตถุเหล่านั้นอ้างอิงถึงวัตถุเดียวกัน
ถ้าหนึ่งในอาร์กิวเมนต์ของ ==
เป็นอ็อบเจ็กต์ และอีกอาร์กิวเมนต์เป็นอ็อบเจ็กต์ดั้งเดิม ดังนั้นอ็อบเจ็กต์จะถูกแปลงเป็นดั้งเดิม ดังที่อธิบายไว้ในบทที่ Object เป็นการแปลงดั้งเดิม
…ยกเว้นค่า null
และ undefined
ซึ่งเท่ากับ ==
กันและกันและไม่มีอะไรอื่นอีก
การเปรียบเทียบที่เข้มงวด ===
นั้นง่ายกว่า เนื่องจากไม่ได้แปลงประเภท
ดังนั้น หากเราเปรียบเทียบอาร์เรย์กับ ==
พวกมันจะไม่เหมือนกัน เว้นแต่เราจะเปรียบเทียบตัวแปรสองตัวที่อ้างอิงถึงอาร์เรย์เดียวกันทุกประการ
ตัวอย่างเช่น:
การแจ้งเตือน ( [] == [] ); // เท็จ การแจ้งเตือน ( [0] == [0] ); // เท็จ
อาร์เรย์เหล่านี้เป็นวัตถุที่แตกต่างกันในทางเทคนิค พวกเขาจึงไม่เท่ากัน ตัวดำเนินการ ==
จะไม่ทำการเปรียบเทียบทีละรายการ
การเปรียบเทียบกับสิ่งดั้งเดิมอาจให้ผลลัพธ์ที่ดูเหมือนแปลกเช่นกัน:
การแจ้งเตือน ( 0 == [] ); // จริง alert('0' == [] ); // เท็จ
ในทั้งสองกรณีนี้ เราจะเปรียบเทียบวัตถุดั้งเดิมกับวัตถุอาร์เรย์ ดังนั้นอาร์เรย์ []
จะถูกแปลงเป็นแบบดั้งเดิมเพื่อจุดประสงค์ในการเปรียบเทียบและกลายเป็นสตริงว่าง ''
จากนั้นกระบวนการเปรียบเทียบจะดำเนินต่อไปด้วยพื้นฐาน ดังที่อธิบายไว้ในบท Type Conversions:
// หลังจาก [] ถูกแปลงเป็น '' การแจ้งเตือน ( 0 == '' ); // จริง เมื่อ '' แปลงเป็นเลข 0 alert('0' == '' ); // false ไม่มีการแปลงประเภท สตริงต่างกัน
แล้วจะเปรียบเทียบอาร์เรย์ได้อย่างไร?
ง่ายมาก: อย่าใช้ตัวดำเนินการ ==
ให้เปรียบเทียบทีละรายการในลูปหรือใช้วิธีการวนซ้ำที่อธิบายไว้ในบทถัดไป
Array เป็นอ็อบเจ็กต์ชนิดพิเศษ เหมาะสำหรับจัดเก็บและจัดการรายการข้อมูลที่เรียงลำดับ
คำประกาศ:
// วงเล็บเหลี่ยม (ปกติ) ให้ arr = [item1, item2...]; // อาร์เรย์ใหม่ (หายากเป็นพิเศษ) ให้ arr = อาร์เรย์ใหม่ (item1, item2...);
การเรียก new Array(number)
จะสร้างอาร์เรย์ตามความยาวที่กำหนด แต่ไม่มีองค์ประกอบ
คุณสมบัติ length
คือความยาวของอาร์เรย์ หรือถ้าให้พูดให้ชัดเจนคือดัชนีตัวเลขสุดท้ายบวกหนึ่ง มันถูกปรับอัตโนมัติโดยวิธีอาเรย์
หากเราลด length
ด้วยตนเอง อาเรย์จะถูกตัดทอน
รับองค์ประกอบ:
เราสามารถรับองค์ประกอบตามดัชนีของมันได้ เช่น arr[0]
นอกจากนี้เรายังสามารถใช้ at(i)
วิธีการที่ช่วยให้ดัชนีติดลบได้ สำหรับค่าลบของ i
จะถอยกลับจากจุดสิ้นสุดของอาร์เรย์ ถ้า i >= 0
มันใช้งานได้เหมือนกับ arr[i]
เราสามารถใช้อาร์เรย์เป็น deque โดยมีการดำเนินการดังต่อไปนี้:
push(...items)
เพิ่ม items
ต่อท้าย
pop()
ลบองค์ประกอบออกจากส่วนท้ายและส่งคืน
shift()
จะลบองค์ประกอบออกจากจุดเริ่มต้นและส่งคืน
unshift(...items)
เพิ่ม items
ไปที่จุดเริ่มต้น
หากต้องการวนซ้ำองค์ประกอบของอาร์เรย์:
for (let i=0; i<arr.length; i++)
– ทำงานได้เร็วที่สุด เข้ากันได้กับเบราว์เซอร์รุ่นเก่า
for (let item of arr)
– ไวยากรณ์สมัยใหม่สำหรับรายการเท่านั้น
for (let i in arr)
- ไม่เคยใช้
หากต้องการเปรียบเทียบอาร์เรย์ อย่าใช้ตัวดำเนินการ ==
(รวมถึง >
, <
และอื่นๆ) เนื่องจากไม่มีการดูแลเป็นพิเศษสำหรับอาร์เรย์ พวกเขาจัดการพวกมันเหมือนเป็นวัตถุใดๆ และนั่นไม่ใช่สิ่งที่เราต้องการโดยทั่วไป
คุณสามารถใช้ for..of
loop เพื่อเปรียบเทียบอาร์เรย์ทีละรายการแทนได้
เราจะดำเนินการต่อด้วยอาร์เรย์และศึกษาวิธีการเพิ่มเติมในการเพิ่ม ลบ แยกองค์ประกอบ และเรียงลำดับอาร์เรย์ในบทถัดไป วิธีการอาร์เรย์
ความสำคัญ: 3
รหัสนี้จะแสดงอะไร?
ให้ผลไม้ = ["แอปเปิ้ล", "ลูกแพร์", "ส้ม"]; // ผลักดันค่าใหม่ลงใน "คัดลอก" ให้ shoppingCart = ผลไม้; shoppingCart.push("กล้วย"); //ในผลไม้มีอะไรบ้าง? การแจ้งเตือน (ผลไม้ความยาว); -
ผลลัพธ์คือ 4
:
ให้ผลไม้ = ["แอปเปิ้ล", "ลูกแพร์", "ส้ม"]; ให้ shoppingCart = ผลไม้; shoppingCart.push("กล้วย"); การแจ้งเตือน (ผลไม้ความยาว); // 4
นั่นเป็นเพราะอาร์เรย์เป็นวัตถุ ดังนั้นทั้ง shoppingCart
และ fruits
จึงมีการอ้างอิงถึงอาร์เรย์เดียวกัน
ความสำคัญ: 5
ลองดำเนินการ 5 อาร์เรย์
สร้าง styles
อาเรย์ด้วยรายการ “Jazz” และ “Blues”
เติม “Rock-n-Roll” ต่อท้าย
แทนที่ค่าที่อยู่ตรงกลางด้วย "Classics" โค้ดของคุณในการค้นหาค่าตรงกลางควรใช้ได้กับอาร์เรย์ใดๆ ที่มีความยาวคี่
ตัดค่าแรกของอาร์เรย์ออกแล้วแสดง
เพิ่ม Rap
และ Reggae
ให้กับอาร์เรย์
อาร์เรย์ในกระบวนการ:
แจ๊ส, บลูส์ แจ๊ส, บลูส์, ร็อกแอนด์โรล แจ๊ส, คลาสสิก, ร็อกแอนด์โรล คลาสสิค, ร็อกแอนด์โรล แร็พ, เร้กเก้, คลาสสิค, ร็อกแอนด์โรล
ให้สไตล์ = ["แจ๊ส", "บลูส์"]; styles.push("ร็อคแอนด์โรล"); styles[Math.floor((styles.length - 1) / 2)] = "คลาสสิก"; การแจ้งเตือน( styles.shift() ); styles.unshift("แร็พ", "เร้กเก้");
ความสำคัญ: 5
ผลลัพธ์คืออะไร? ทำไม
ให้ arr = ["a", "b"]; arr.push(ฟังก์ชั่น() { การแจ้งเตือน (นี้); - ถึง[2](); -
การเรียก arr[2]()
เป็นรูปแบบเก่าที่ดีทางวากยสัมพันธ์ obj[method]()
ในบทบาทของ obj
ที่เรามี arr
และในบทบาทของ method
ที่เรามี 2
ดังนั้นเราจึงมีการเรียกใช้ฟังก์ชัน arr[2]
เป็นวิธีการของวัตถุ โดยปกติแล้วจะได้รับ this
โดยอ้างอิงถึงวัตถุ arr
และส่งออกอาร์เรย์:
ให้ arr = ["a", "b"]; arr.push(ฟังก์ชั่น() { การแจ้งเตือน (นี้); - ถึง[2](); // a,b,ฟังก์ชัน(){...}
อาร์เรย์มี 3 ค่า ในตอนแรกจะมีค่า 2 ค่า บวกด้วยฟังก์ชัน
ความสำคัญ: 4
เขียนฟังก์ชัน sumInput()
ว่า:
ถามผู้ใช้เกี่ยวกับค่าโดยใช้ prompt
และเก็บค่าไว้ในอาร์เรย์
เสร็จสิ้นการถามเมื่อผู้ใช้ป้อนค่าที่ไม่ใช่ตัวเลข สตริงว่าง หรือกด "ยกเลิก"
คำนวณและส่งกลับผลรวมของรายการอาร์เรย์
PS ศูนย์ 0
เป็นตัวเลขที่ถูกต้อง โปรดอย่าหยุดอินพุตเป็นศูนย์
เรียกใช้การสาธิต
โปรดสังเกตรายละเอียดการแก้ปัญหาที่ละเอียดอ่อนแต่สำคัญ เราจะไม่แปลง value
เป็นตัวเลขทันทีหลังจาก prompt
เนื่องจากหลังจาก value = +value
เราจะไม่สามารถบอกสตริงว่าง (เครื่องหมายหยุด) จากศูนย์ (ตัวเลขที่ถูกต้อง) เราทำทีหลังแทน
ฟังก์ชั่น sumInput() { ให้ตัวเลข = []; ในขณะที่ (จริง) { ให้ value = prompt("ขอตัวเลขหน่อยได้ไหม?", 0); //เราควรยกเลิกมั้ย? if (value === "" || value === null || !isFinite(value)) แตก; ตัวเลข.ผลักดัน(+ค่า); - ให้ผลรวม = 0; สำหรับ (ให้จำนวนตัวเลข) { ผลรวม += จำนวน; - จำนวนเงินที่ส่งคืน; - การแจ้งเตือน( sumInput() );
ความสำคัญ: 2
ข้อมูลเข้าเป็นอาร์เรย์ของตัวเลข เช่น arr = [1, -2, 3, 4, -9, 6]
ภารกิจคือ: ค้นหาอาร์เรย์ย่อยที่ต่อเนื่องกันของ arr
ด้วยผลรวมสูงสุดของรายการ
เขียนฟังก์ชัน getMaxSubSum(arr)
ที่จะส่งคืนผลรวมนั้น
ตัวอย่างเช่น:
getMaxSubSum([-1, 2, 3, -9]) == 5 (ผลรวมของรายการที่ไฮไลต์) getMaxSubSum([2, -1, 2, 3, -9]) == 6 getMaxSubSum([-1, 2, 3, -9, 11]) == 11 getMaxSubSum([-2, -1, 1, 2]) == 3 getMaxSubSum([100, -9, 2, -3, 5]) == 100 getMaxSubSum([1, 2, 3]) == 6 (รับทั้งหมด)
ถ้ารายการทั้งหมดเป็นลบ หมายความว่าเราไม่เอาเลย (อาร์เรย์ย่อยว่างเปล่า) ดังนั้นผลรวมจึงเป็นศูนย์:
getMaxSubSum([-1, -2, -3]) = 0
โปรดลองคิดวิธีแก้ปัญหาที่รวดเร็ว: O(n 2 ) หรือแม้แต่ O(n) ถ้าทำได้
เปิดแซนด์บ็อกซ์พร้อมการทดสอบ
เราสามารถคำนวณผลรวมย่อยที่เป็นไปได้ทั้งหมด
วิธีที่ง่ายที่สุดคือนำทุกองค์ประกอบมาคำนวณผลรวมของอาร์เรย์ย่อยทั้งหมดโดยเริ่มจากองค์ประกอบนั้น
ตัวอย่างเช่น สำหรับ [-1, 2, 3, -9, 11]
:
// เริ่มจาก -1: -1 -1 + 2 -1 + 2 + 3 -1 + 2 + 3 + (-9) -1 + 2 + 3 + (-9) + 11 // เริ่มจาก 2: 2 2 + 3 2 + 3 + (-9) 2 + 3 + (-9) + 11 // เริ่มจาก 3: 3 3 + (-9) 3 + (-9) + 11 // เริ่มจาก -9 -9 -9 + 11 // เริ่มตั้งแต่ 11 11
จริงๆ แล้วโค้ดเป็นการวนซ้ำแบบซ้อน: การวนซ้ำภายนอกเหนือองค์ประกอบอาร์เรย์ และจำนวนภายในนับผลรวมย่อยที่เริ่มต้นด้วยองค์ประกอบปัจจุบัน
ฟังก์ชั่น getMaxSubSum (arr) { ให้ maxSum = 0; // ถ้าเราไม่มีองค์ประกอบใด ๆ ก็จะส่งกลับค่าศูนย์ สำหรับ (ให้ i = 0; i < arr.length; i++) { ให้ sumFixedStart = 0; สำหรับ (ให้ j = i; j < arr.length; j++) { sumFixedStart += arr[j]; maxSum = Math.max(maxSum, sumFixedStart); - - กลับ maxSum; - การแจ้งเตือน( getMaxSubSum([-1, 2, 3, -9]) ); // 5 การแจ้งเตือน( getMaxSubSum([-1, 2, 3, -9, 11]) ); // 11 การแจ้งเตือน( getMaxSubSum([-2, -1, 1, 2]) ); // 3 การแจ้งเตือน( getMaxSubSum([1, 2, 3]) ); // 6 การแจ้งเตือน( getMaxSubSum([100, -9, 2, -3, 5]) ); // 100
สารละลายมีความซับซ้อนด้านเวลาเป็น O(n 2 ) กล่าวอีกนัยหนึ่ง ถ้าเราเพิ่มขนาดอาร์เรย์ 2 เท่า อัลกอริธึมจะทำงานนานขึ้น 4 เท่า
สำหรับอาร์เรย์ขนาดใหญ่ (1,000, 10,000 รายการขึ้นไป) อัลกอริธึมดังกล่าวอาจทำให้เกิดความล่าช้าอย่างรุนแรง
มาดูอาร์เรย์และเก็บผลรวมบางส่วนขององค์ประกอบปัจจุบันไว้ในตัวแปร s
ถ้า s
กลายเป็นลบ ณ จุดใดจุดหนึ่ง ให้กำหนด s=0
ค่าสูงสุดของ s
ดังกล่าวทั้งหมดจะเป็นคำตอบ
หากคำอธิบายคลุมเครือเกินไป โปรดดูโค้ด เนื่องจากสั้นพอ:
ฟังก์ชั่น getMaxSubSum (arr) { ให้ maxSum = 0; ให้ผลรวมบางส่วน = 0; สำหรับ (ให้รายการของ arr) { // สำหรับแต่ละรายการของ arr PartialSum += รายการ; // เพิ่มลงใน PartialSum maxSum = Math.max(maxSum, ผลรวมบางส่วน); //จำสูงสุด ถ้า (ผลรวมบางส่วน < 0) ผลรวมบางส่วน = 0; // เป็นศูนย์ถ้าเป็นลบ - กลับ maxSum; - การแจ้งเตือน( getMaxSubSum([-1, 2, 3, -9]) ); // 5 การแจ้งเตือน( getMaxSubSum([-1, 2, 3, -9, 11]) ); // 11 การแจ้งเตือน( getMaxSubSum([-2, -1, 1, 2]) ); // 3 การแจ้งเตือน( getMaxSubSum([100, -9, 2, -3, 5]) ); // 100 การแจ้งเตือน( getMaxSubSum([1, 2, 3]) ); // 6 การแจ้งเตือน( getMaxSubSum([-1, -2, -3]) ); // 0
อัลกอริธึมต้องการการส่งผ่านอาร์เรย์ 1 ครั้ง ดังนั้นความซับซ้อนของเวลาคือ O(n)
คุณสามารถดูข้อมูลโดยละเอียดเพิ่มเติมเกี่ยวกับอัลกอริทึมได้ที่นี่: ปัญหาอาร์เรย์ย่อยสูงสุด หากยังไม่ชัดเจนว่าเหตุใดจึงใช้งานได้ โปรดติดตามอัลกอริทึมในตัวอย่างด้านบน ดูวิธีการทำงาน ซึ่งดีกว่าคำใดๆ
เปิดโซลูชันพร้อมการทดสอบในแซนด์บ็อกซ์