คำอธิบาย [] .slice.call เป็น javascript หรือไม่


197

ฉันสะดุดทางลัดที่เป็นระเบียบนี้สำหรับการแปลง DOM NodeList ไปเป็นอาร์เรย์ปกติ แต่ฉันต้องยอมรับว่าฉันไม่เข้าใจวิธีการทำงานอย่างสมบูรณ์:

[].slice.call(document.querySelectorAll('a'), 0)

ดังนั้นเริ่มต้นด้วยอาร์เรย์ที่ว่างเปล่า[]จากนั้นsliceจะใช้ในการแปลงผลลัพธ์ของcallการเป็นอาร์เรย์ใหม่ใช่หรือไม่

callบิตที่ผมไม่เข้าใจคือ ที่แปลงdocument.querySelectorAll('a')จาก NodeList เป็นอาร์เรย์ปกติได้อย่างไร


5
Array.prototype.slice.call(document.querySelectorAll('a'));เป็นวิธีที่เหมาะสมในการเขียนโค้ดที่คุณเขียน
vdegenne

4
BTW ทันสมัย (และเข้าใจได้อย่างสังหรณ์ใจ) วิธี ES6 Array.fromสำหรับเป็นเหมือนกัน ดังนั้นเช่นนี้จะทำเช่นเดียวกัน: Array.from (document.querySelectorAll ('a'));
rugk

คำตอบ:


158

สิ่งที่เกิดขึ้นที่นี่เป็นที่ที่คุณเรียกslice()ราวกับว่ามันเป็นฟังก์ชั่นของการใช้NodeList call()สิ่งที่slice()ไม่อยู่ในกรณีนี้คือการสร้างอาร์เรย์ว่างแล้วย้ำผ่านวัตถุที่มันทำงานบน ( แต่เดิมอาร์เรย์ตอนนี้NodeList) และให้ท้ายองค์ประกอบของวัตถุนั้นไปยังอาร์เรย์ที่ว่างเปล่ามันสร้างขึ้นซึ่งในที่สุดก็จะถูกส่งกลับ นี่เป็นบทความเกี่ยวกับเรื่องนี้

แก้ไข:

ดังนั้นจึงเริ่มต้นด้วยอาร์เรย์ที่ว่าง [] จากนั้นจะใช้การแปลงผลการโทรเป็นอาร์เรย์ใหม่ใช่หรือไม่

ไม่ถูกต้อง [].sliceส่งคืนวัตถุฟังก์ชั่น ฟังก์ชั่นวัตถุมีฟังก์ชั่นcall()ที่เรียกใช้ฟังก์ชั่นการกำหนดพารามิเตอร์แรกของcall()ถึงthis; กล่าวอีกนัยหนึ่งการทำให้ฟังก์ชันคิดว่ามันถูกเรียกจากพารามิเตอร์ (ที่NodeListส่งคืนโดยdocument.querySelectorAll('a')) แทนที่จะมาจากอาร์เรย์


59
โปรดสังเกตที่นี่ด้วยว่าสิ่งนี้มีความหมายเทียบเท่ากับการพูดArray.prototype.slice.call(...)แต่จริงๆแล้วมันจะยกตัวอย่างวัตถุอาเรย์ ( []) เพื่อเข้าถึงวิธีสไลซ์ต้นแบบเท่านั้น นั่นคือการเริ่มต้นที่สิ้นเปลือง พูดArray.prototype.slice.call(...)แทนคือทำความสะอาดถึงแม้ว่าคุณจะเพิ่มตัวละครหลายอย่างเพื่อ JS ของคุณถ้าคุณกำลังนับ ...
เบน Zotto

โปรดทราบว่าสิ่งนี้ใช้ได้กับ IE 8 และด้านล่างเฉพาะกับ Array objects เท่านั้นดังนั้นคุณจะไม่สามารถเลียนแบบNodeListได้
Livingston Samuel

5
@quixoto []มีความน่าเชื่อถือมากกว่าเนื่องจากArrayสามารถเขียนทับสิ่งอื่นได้ หากคุณต้องการนำมาใช้ซ้ำขอArray#sliceแนะนำให้ทำการแคช
Mathias Bynens

2
ในกรณีที่คนอื่นจะมองหาวิธีการที่จะทำเช่นนี้ใน IE8 ให้ตรวจสอบคำถามนี้stackoverflow.com/questions/3199588/...
เลียม Newmarch

1
ฉันเห็นรูปแบบนี้ปรากฏในซอร์สโค้ด backbone.js: var array = []; var push = array.push; var slice = array.slice; var splice = array.splice;เขาทำเพื่อความปลอดภัย @MathiasBynens หรือไม่?
owensmartin

125

ใน JavaScript วิธีการของวัตถุสามารถเชื่อมโยงกับวัตถุอื่นเมื่อรันไทม์ ในระยะสั้นจาวาสคริปต์อนุญาตให้วัตถุ "ยืม" วิธีการของวัตถุอื่น:

object1 = {
    name: 'Frank',
    greet() {
        alert(`Hello ${this.name}`);
    }
};

object2 = {
    name: 'Andy'
};

// Note that object2 has no greet method,
// but we may "borrow" from object1:

object1.greet.call(object2); // Will show an alert with 'Hello Andy'

callและapplyวิธีการของวัตถุที่ฟังก์ชั่น (ใน JavaScript, ฟังก์ชั่นเป็นวัตถุเช่นกัน) ช่วยให้คุณสามารถทำเช่นนี้ ดังนั้นในรหัสของคุณคุณสามารถพูดได้ว่า NodeList ยืมวิธีการแบ่งส่วนของอาร์เรย์ .slice()ส่งคืนอาเรย์อีกอันตามผลลัพธ์ซึ่งจะกลายเป็นอาเรย์ที่ถูกแปลงซึ่งคุณสามารถใช้ได้


แบง on 🎯คำอธิบายแนวคิดนามธรรมสำหรับฟังก์ชั่นของวัตถุจาวาสคริปต์ ตอนนี้คุณสามารถนำไปใช้สำหรับcallฟังก์ชั่นของArray.prototypeaka [].prototypeด้วยตัวคุณเอง
Sourabh

29

จะดึงเอาฟังก์ชั่นจากslice Arrayจากนั้นเรียกใช้ฟังก์ชันนั้น แต่ใช้ผลลัพธ์document.querySelectorAllเป็นthisวัตถุแทนอาร์เรย์จริง


19

มันเป็นเทคนิคในการแปลงวัตถุเหมือนอาร์เรย์เป็นอาร์เรย์จริง

บางส่วนของวัตถุเหล่านี้รวมถึง:

  • arguments ในฟังก์ชั่น
  • NodeList (โปรดจำไว้ว่าเนื้อหาของพวกเขาสามารถเปลี่ยนแปลงได้หลังจากถูกดึงมาแล้ว!
  • jQuery collection, aka วัตถุ jQuery (doc บางตัว: API , ชนิด , เรียนรู้ )

บริการนี้มีวัตถุประสงค์มากมายเช่นวัตถุจะถูกส่งผ่านโดยการอ้างอิงในขณะที่อาร์เรย์จะถูกส่งผ่านตามค่า

นอกจากนี้โปรดทราบอาร์กิวเมนต์แรก0สามารถ omited, คำอธิบายอย่างละเอียดที่นี่

และเพื่อประโยชน์ของความสมบูรณ์นอกจากนี้ยังมีjQuery.makeArray ()


15

มันแปลงdocument.querySelectorAll('a')จาก a NodeList ไปเป็น array ปกติได้อย่างไร?

นี่คือรหัสที่เรามี

[].slice.call(document.querySelectorAll('a'), 0)

ให้รื้อมันก่อน

  []    // Array object
.slice // Accessing the function 'slice' present in the prototype of Array
.call // Accessing the function 'call' present in the prototype of function object(slice)
(document.querySelectorAll('a'),0) 
    // 'call' can have arguments like, (thisArg, arg1,arg2...n). 
   // So here we are passing the 'thisArg' as an array like object,
  // that is a 'nodeList'. It will be served as 'this' object inside of slice function.
 // And finally setting 'start' argument of slice as '0' and leaving the 'end' 
// argument as 'undefined'

ขั้นตอนที่ 1 การดำเนินการของcallฟังก์ชั่น

  • ภายในcallนอกเหนือthisArgจากนั้นอาร์กิวเมนต์ที่เหลือจะถูกผนวกเข้ากับรายการอาร์กิวเมนต์
  • ตอนนี้ฟังก์ชั่นsliceจะถูกเรียกใช้โดยการผูกthisค่าเป็น thisArg(อาร์เรย์เหมือนวัตถุมาจากdocument.querySelector) และมีรายการอาร์กิวเมนต์ ie] อาร์กิวเมนต์startที่มี0

ขั้นตอนที่ 2: sliceเรียกใช้งานฟังก์ชันภายในcall

  • startจะถูกกำหนดให้กับตัวแปรsเป็น0
  • ตั้งแต่endเป็นundefined, this.lengthจะถูกเก็บไว้ในe
  • อาร์เรย์ที่ว่างจะถูกเก็บไว้ในตัวแปร a
  • หลังจากทำการตั้งค่าข้างต้นการทำซ้ำต่อไปนี้จะเกิดขึ้น

    while(s < e) {
      a.push(this[s]);
      s++;
    }
  • อาร์เรย์ที่เติมaจะถูกส่งคืนเป็นผลลัพธ์

PS สำหรับการทำความเข้าใจที่ดีขึ้นของสถานการณ์ของเราขั้นตอนบางอย่างที่จำเป็นสำหรับบริบทของเราได้รับการปฏิเสธจากขั้นตอนวิธีการเดิมของการโทรและชิ้น


1
คำอธิบายทีละขั้นตอนที่ดีมาก ! น่ากลัว ขอบคุณ :)
kittu

1
คำอธิบายที่ดี
NaveenDA

7
[].slice.call(document.querySelectorAll('.slide'));

1. The querySelectorAll() method returns all elements in the document that matches a specified selector(s). 

2. The call() method calls a function with a given this value and arguments provided individually.

3. The slice() method returns the selected elements in an array, as a new array object.

  so this line return the array of [object HTMLDivElement]. Here is the six div with classname "slide" so array length will be 6.

<div class="slideshow">

  <div class="slide">
    first slider1
  </div>
  <div class="slide">
    first slider2
  </div>
  <div class="slide">
    first slider3
  </div>
  <div class="slide">
    first slider4
  </div>
  <div class="slide">
    first slider5
  </div>
  <div class="slide">
    first slider6
  </div>

</div>

<script type="text/javascript">

  var arraylist = [].slice.call(document.querySelectorAll('.slide'));

  alert(arraylist);

</script>

4

จาก ES6: เพียงแค่สร้างอาร์เรย์ด้วยArray.from (element.children)หรือArray.from ({length: 5})

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