ฟังก์ชันในตัว JavaScript จำนวนมากรองรับอาร์กิวเมนต์จำนวนเท่าใดก็ได้
ตัวอย่างเช่น:
Math.max(arg1, arg2, ..., argN)
– ส่งคืนค่าอาร์กิวเมนต์ที่ยิ่งใหญ่ที่สุด
Object.assign(dest, src1, ..., srcN)
– คัดลอกคุณสมบัติจาก src1..N
ลงใน dest
…และอื่นๆ
ในบทนี้เราจะเรียนรู้วิธีการทำเช่นเดียวกัน และวิธีส่งผ่านอาร์เรย์ไปยังฟังก์ชันต่างๆ เช่น พารามิเตอร์
...
สามารถเรียกใช้ฟังก์ชันด้วยอาร์กิวเมนต์จำนวนเท่าใดก็ได้ ไม่ว่าจะกำหนดไว้อย่างไรก็ตาม
ชอบที่นี่:
ผลรวมฟังก์ชัน (a, b) { กลับ + b; - การแจ้งเตือน( ผลรวม(1, 2, 3, 4, 5) );
จะไม่มีข้อผิดพลาดเนื่องจากการโต้แย้ง "มากเกินไป" แต่แน่นอนว่าผลลัพธ์จะนับเฉพาะสองรายการแรก ดังนั้นผลลัพธ์ในโค้ดด้านบนคือ 3
พารามิเตอร์ที่เหลือสามารถรวมไว้ในคำจำกัดความของฟังก์ชันได้โดยใช้จุดสามจุด ...
ตามด้วยชื่อของอาร์เรย์ที่จะมีพารามิเตอร์เหล่านั้น จุดหมายถึง "รวบรวมพารามิเตอร์ที่เหลือลงในอาร์เรย์"
ตัวอย่างเช่น หากต้องการรวบรวมข้อโต้แย้งทั้งหมดลงในอาร์เรย์ args
:
function sumAll(...args) { // args เป็นชื่อของอาร์เรย์ ให้ผลรวม = 0; สำหรับ (ให้หาเรื่องหาเรื่อง) ผลรวม += หาเรื่อง; จำนวนเงินที่ส่งคืน; - การแจ้งเตือน( sumAll(1) ); // 1 การแจ้งเตือน( sumAll(1, 2) ); // 3 การแจ้งเตือน( sumAll(1, 2, 3) ); // 6
เราสามารถเลือกรับพารามิเตอร์แรกเป็นตัวแปร และรวบรวมเฉพาะส่วนที่เหลือได้
อาร์กิวเมนต์สองข้อแรกจะเข้าสู่ตัวแปร และส่วนที่เหลือจะเข้าสู่อาร์เรย์ titles
:
ฟังก์ชั่น showName (ชื่อ, นามสกุล, ... ชื่อ) { การแจ้งเตือน( ชื่อ + ' ' + นามสกุล ); //จูเลียส ซีซาร์ // ส่วนที่เหลือไปอยู่ในอาร์เรย์ชื่อ // เช่น titles = ["กงสุล", "นเรศวร"] การแจ้งเตือน (หัวเรื่อง[0] ); //กงสุล การแจ้งเตือน( หัวเรื่อง[1] ); //นเรศวร การแจ้งเตือน( titles.length ); // 2 - showName("จูเลียส", "ซีซาร์", "กงสุล", "นเรศวร");
พารามิเตอร์ที่เหลือจะต้องอยู่ท้ายสุด
พารามิเตอร์ที่เหลือจะรวบรวมอาร์กิวเมนต์ที่เหลือทั้งหมด ดังนั้นค่าต่อไปนี้จึงไม่สมเหตุสมผลและทำให้เกิดข้อผิดพลาด:
ฟังก์ชั่น f(arg1, ...rest, arg2) { // arg2 หลังจาก ...rest ?! // ข้อผิดพลาด -
...rest
จะต้องคงอยู่ตลอดไป
นอกจากนี้ยังมีอ็อบเจ็กต์พิเศษที่มีลักษณะคล้ายอาเรย์ชื่อ arguments
ซึ่งมีอาร์กิวเมนต์ทั้งหมดตามดัชนี
ตัวอย่างเช่น:
ฟังก์ชั่น showName() { การแจ้งเตือน (ข้อโต้แย้ง. ความยาว); การแจ้งเตือน ( ข้อโต้แย้ง [0] ); การแจ้งเตือน ( ข้อโต้แย้ง [1] ); // มันทำซ้ำได้ // สำหรับ (ให้ข้อโต้แย้ง) การแจ้งเตือน (arg); - // แสดง: 2, จูเลียส, ซีซาร์ showName("จูเลียส", "ซีซาร์"); // แสดง: 1, Ilya, ไม่ได้กำหนด (ไม่มีอาร์กิวเมนต์ที่สอง) showName("อิลยา");
ในสมัยก่อน พารามิเตอร์ส่วนที่เหลือไม่มีอยู่ในภาษา และการใช้ arguments
เป็นวิธีเดียวที่จะได้รับอาร์กิวเมนต์ทั้งหมดของฟังก์ชัน และมันยังใช้งานได้ เราสามารถค้นหามันได้ในโค้ดเก่า
แต่ข้อเสียก็คือ แม้ว่า arguments
จะมีลักษณะเหมือนอาร์เรย์และสามารถวนซ้ำได้ แต่ก็ไม่ใช่อาร์เรย์ มันไม่รองรับเมธอดอาร์เรย์ ดังนั้นเราจึงไม่สามารถเรียก arguments.map(...)
ได้
นอกจากนี้ยังประกอบด้วยข้อโต้แย้งทั้งหมดเสมอ เราไม่สามารถจับพวกมันได้เพียงบางส่วน เหมือนกับที่เราทำกับพารามิเตอร์ที่เหลือ
ดังนั้นเมื่อเราต้องการคุณสมบัติเหล่านี้ พารามิเตอร์ที่เหลือจึงเป็นที่ต้องการ
ฟังก์ชันลูกศรไม่มี "arguments"
หากเราเข้าถึงอ็อบเจ็กต์ arguments
จากฟังก์ชันลูกศร มันจะรับมันจากฟังก์ชัน "ปกติ" ภายนอก
นี่คือตัวอย่าง:
ฟังก์ชัน ฉ() { ให้ showArg = () => การแจ้งเตือน (อาร์กิวเมนต์ [0]); showArg(); - ฉ(1); // 1
อย่างที่เราจำได้ ฟังก์ชั่นลูกศรไม่มี this
เป็นของตัวเอง ตอนนี้เรารู้ว่าพวกเขาไม่มีวัตถุ arguments
พิเศษเช่นกัน
เราเพิ่งเห็นวิธีการรับอาร์เรย์จากรายการพารามิเตอร์
แต่บางครั้งเราจำเป็นต้องทำตรงกันข้าม
ตัวอย่างเช่น มีฟังก์ชัน Math.max ในตัวที่ส่งคืนตัวเลขที่ยิ่งใหญ่ที่สุดจากรายการ:
การแจ้งเตือน( Math.max(3, 5, 1) ); // 5
ตอนนี้สมมติว่าเรามีอาร์เรย์ [3, 5, 1]
เราจะเรียกมันว่า Math.max
ได้อย่างไร?
การส่งผ่าน "ตามที่เป็น" จะไม่ทำงาน เนื่องจาก Math.max
ต้องการรายการอาร์กิวเมนต์ที่เป็นตัวเลข ไม่ใช่อาร์เรย์เดียว:
ให้ arr = [3, 5, 1]; การแจ้งเตือน( Math.max(arr) ); // แนน
และแน่นอนว่าเราไม่สามารถแสดงรายการต่างๆ ในโค้ดได้ด้วยตนเอง Math.max(arr[0], arr[1], arr[2])
เนื่องจากเราอาจไม่แน่ใจว่ามีกี่รายการ ในขณะที่สคริปต์ของเราทำงาน อาจมีจำนวนมากหรือไม่มีเลย และนั่นจะน่าเกลียด
กระจายไวยากรณ์ เพื่อช่วยเหลือ! ดูเหมือนพารามิเตอร์ที่เหลือเช่นกันโดยใช้ ...
แต่ค่อนข้างตรงกันข้าม
เมื่อ ...arr
ถูกใช้ในการเรียกใช้ฟังก์ชัน มันจะ "ขยาย" อ็อบเจ็กต์ arr
ที่สามารถวนซ้ำได้เข้าไปในรายการอาร์กิวเมนต์
สำหรับ Math.max
:
ให้ arr = [3, 5, 1]; alert( Math.max(...arr) ); // 5 (สเปรดเปลี่ยนอาร์เรย์เป็นรายการอาร์กิวเมนต์)
นอกจากนี้เรายังสามารถส่งผ่าน iterable ได้หลายรายการด้วยวิธีนี้:
ให้ arr1 = [1, -2, 3, 4]; ให้ arr2 = [8, 3, -8, 1]; alert( Math.max(...arr1, ...arr2) ); // 8
เรายังสามารถรวมไวยากรณ์สเปรดเข้ากับค่าปกติได้:
ให้ arr1 = [1, -2, 3, 4]; ให้ arr2 = [8, 3, -8, 1]; alert( Math.max(1, ...arr1, 2, ...arr2, 25) ); // 25
นอกจากนี้ ไวยากรณ์การแพร่กระจายสามารถใช้เพื่อรวมอาร์เรย์ได้:
ให้ arr = [3, 5, 1]; ให้ arr2 = [8, 9, 15]; ให้ผสาน = [0, ...arr, 2, ...arr2]; การแจ้งเตือน (รวม); // 0,3,5,1,2,8,9,15 (0 จากนั้น arr จากนั้น 2 จากนั้น arr2)
ในตัวอย่างข้างต้น เราใช้อาร์เรย์เพื่อแสดงไวยากรณ์ของการแพร่กระจาย แต่การทำซ้ำใดๆ ก็สามารถทำได้
ตัวอย่างเช่น เราใช้ไวยากรณ์การแพร่กระจายเพื่อเปลี่ยนสตริงให้เป็นอาร์เรย์ของอักขระ:
ให้ str = "สวัสดี"; การแจ้งเตือน( [...str] ); // สวัสดี
ไวยากรณ์การแพร่กระจายใช้ตัววนซ้ำภายในเพื่อรวบรวมองค์ประกอบ เช่นเดียวกับ for..of
ดังนั้นสำหรับสตริง for..of
ส่งคืนอักขระและ ...str
กลายเป็น "H","e","l","l","o"
รายการอักขระจะถูกส่งไปยัง array Initializer [...str]
สำหรับงานเฉพาะนี้ เราสามารถใช้ Array.from
ได้เช่นกัน เนื่องจากมันจะแปลงค่าที่ทำซ้ำได้ (เช่น สตริง) ให้เป็นอาร์เรย์:
ให้ str = "สวัสดี"; // Array.from แปลงค่าที่ทำซ้ำได้ให้เป็นอาร์เรย์ การแจ้งเตือน( Array.from(str) ); // สวัสดี
ผลลัพธ์จะเหมือนกับ [...str]
แต่มีความแตกต่างเล็กน้อยระหว่าง Array.from(obj)
และ [...obj]
:
Array.from
ทำงานทั้งแบบ array-like และ iterable
ไวยากรณ์สเปรดใช้ได้กับ iterable เท่านั้น
ดังนั้นสำหรับงานเปลี่ยนบางสิ่งให้เป็นอาร์เรย์ Array.from
มีแนวโน้มที่จะเป็นสากลมากกว่า
จำได้ไหมเมื่อเราพูดถึง Object.assign()
ในอดีต?
เป็นไปได้ที่จะทำสิ่งเดียวกันกับไวยากรณ์การแพร่กระจาย
ให้ arr = [1, 2, 3]; ให้ arrCopy = [...arr]; // กระจายอาร์เรย์ไปยังรายการพารามิเตอร์ // จากนั้นนำผลลัพธ์ไปใส่ในอาร์เรย์ใหม่ // อาร์เรย์มีเนื้อหาเหมือนกันหรือไม่? การแจ้งเตือน (JSON.stringify(arr) === JSON.stringify(arrCopy)); // จริง // อาร์เรย์เท่ากันหรือไม่? การแจ้งเตือน (arr === arrCopy); // false (ไม่ใช่ข้อมูลอ้างอิงเดียวกัน) // การแก้ไขอาร์เรย์เริ่มต้นของเราจะไม่แก้ไขสำเนา: arr.ผลักดัน(4); การแจ้งเตือน(arr); // 1, 2, 3, 4 การแจ้งเตือน (arrCopy); // 1, 2, 3
โปรดทราบว่าคุณสามารถทำสิ่งเดียวกันนี้เพื่อทำสำเนาออบเจ็กต์ได้:
ให้ obj = { a: 1, b: 2, c: 3 }; ให้ objCopy = { ...obj }; // กระจายวัตถุไปยังรายการพารามิเตอร์ // จากนั้นส่งคืนผลลัพธ์ในวัตถุใหม่ // วัตถุมีเนื้อหาเหมือนกันหรือไม่? การแจ้งเตือน (JSON.stringify(obj) === JSON.stringify(objCopy)); // จริง // วัตถุเท่ากันหรือไม่? การแจ้งเตือน (obj === objCopy); // false (ไม่ใช่ข้อมูลอ้างอิงเดียวกัน) // การแก้ไขวัตถุเริ่มต้นของเราจะไม่แก้ไขสำเนา: obj.d = 4; การแจ้งเตือน (JSON.stringify (obj)); // {"ก":1,"ข":2,"ค":3,"ง":4} การแจ้งเตือน (JSON.stringify (objCopy)); // {"ก":1,"ข":2,"ค":3}
วิธีการคัดลอกอ็อบเจ็กต์นี้จะสั้นกว่า let objCopy = Object.assign({}, obj)
มาก หรือสำหรับอาร์เรย์ let arrCopy = Object.assign([], arr)
ดังนั้นเราจึงชอบใช้มันทุกครั้งที่ทำได้
เมื่อเราเห็น "..."
ในโค้ด อาจเป็นพารามิเตอร์ที่เหลือหรือไวยากรณ์การแพร่กระจาย
มีวิธีง่ายๆ ในการแยกแยะระหว่างสิ่งเหล่านี้:
เมื่อ ...
อยู่ที่ส่วนท้ายของพารามิเตอร์ฟังก์ชัน จะเป็น "พารามิเตอร์ที่เหลือ" และรวบรวมรายการอาร์กิวเมนต์ที่เหลือลงในอาร์เรย์
เมื่อ ...
เกิดขึ้นในการเรียกใช้ฟังก์ชันหรือคล้ายกัน จะเรียกว่า "ไวยากรณ์การแพร่กระจาย" และขยายอาร์เรย์ออกเป็นรายการ
ใช้รูปแบบ:
พารามิเตอร์ส่วนที่เหลือใช้เพื่อสร้างฟังก์ชันที่ยอมรับอาร์กิวเมนต์จำนวนเท่าใดก็ได้
ไวยากรณ์การแพร่กระจายใช้เพื่อส่งผ่านอาร์เรย์ไปยังฟังก์ชันที่ปกติต้องใช้รายการอาร์กิวเมนต์จำนวนมาก
เมื่อรวมกันแล้วจะช่วยเดินทางระหว่างรายการและอาร์เรย์ของพารามิเตอร์ได้อย่างง่ายดาย
อาร์กิวเมนต์ทั้งหมดของการเรียกใช้ฟังก์ชันยังมีอยู่ใน arguments
"แบบเก่า" : วัตถุที่ทำซ้ำได้เหมือนอาร์เรย์