Penjelasan [] .slice.call dalam javascript?

197

Saya menemukan jalan pintas yang rapi ini untuk mengubah DOM NodeList menjadi array biasa, tetapi harus saya akui, saya tidak sepenuhnya mengerti cara kerjanya:

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

Jadi itu dimulai dengan array kosong [], lalu slicedigunakan untuk mengkonversi hasil callke array baru ya?

Bagian yang saya tidak mengerti adalah call. Bagaimana cara mengonversi document.querySelectorAll('a')dari NodeList ke array biasa?

Yansky
sumber
5
Array.prototype.slice.call(document.querySelectorAll('a'));adalah cara yang tepat untuk menulis potongan kode yang Anda tulis.
vdegenne
4
BTW, metode ES6 modern (dan dapat dimengerti secara intuitif) untuk hal yang sama adalah Array.from. Jadi misalnya ini akan melakukan hal yang sama: Array.from (document.querySelectorAll ('a'));
rugk

Jawaban:

158

Apa yang terjadi di sini adalah bahwa Anda memanggil slice()seolah-olah itu adalah fungsi NodeListmenggunakan call(). Apa yang slice()dilakukan dalam kasus ini adalah membuat array kosong, kemudian beralih melalui objek yang sedang berjalan (awalnya array, sekarang a NodeList) dan terus menambahkan elemen objek ke array kosong yang dibuatnya, yang akhirnya dikembalikan. Inilah artikel tentang ini .

EDIT:

Jadi itu dimulai dengan array kosong [], kemudian slice digunakan untuk mengonversi hasil panggilan ke array baru ya?

Itu tidak benar. [].slicemengembalikan objek fungsi. Objek fungsi memiliki fungsi call()yang memanggil fungsi yang menetapkan parameter pertama dari call()to this; dengan kata lain, membuat fungsi berpikir bahwa itu dipanggil dari parameter (yang NodeListdikembalikan oleh document.querySelectorAll('a')) daripada dari array.

Max Shawabkeh
sumber
59
Perhatikan juga di sini bahwa meskipun ini secara semantik sama dengan mengatakan Array.prototype.slice.call(...), ia sebenarnya instantiate objek array ( []) hanya untuk mengakses metode slice prototipe-nya. Itu adalah contoh yang sia-sia. Mengatakan Array.prototype.slice.call(...)sebaliknya lebih bersih, meskipun Anda menambahkan beberapa karakter ke JS jika Anda menghitung ...
Ben Zotto
Perhatikan bahwa ini bekerja di IE 8 dan di bawah ini hanya pada objek Array, sehingga Anda tidak akan dapat mengkloning NodeLists
Livingston Samuel
5
@quixoto []lebih dapat diandalkan karena Arraydapat ditimpa dengan sesuatu yang lain. Jika Anda perlu menggunakan kembali Array#slice, itu ide yang baik untuk menyimpannya.
Mathias Bynens
2
Jika ada orang lain yang mencari cara untuk melakukan ini di IE8, lihat pertanyaan ini stackoverflow.com/questions/3199588/…
Liam Newmarch
1
Saya benar-benar melihat pola ini muncul di kode sumber backbone.js: var array = []; var push = array.push; var slice = array.slice; var splice = array.splice;Apakah dia melakukan ini untuk masalah keamanan @MathiasBynens menyebutkan?
owensmartin
125

Dalam JavaScript, metode suatu objek dapat terikat ke objek lain saat runtime. Singkatnya, javascript memungkinkan suatu objek untuk "meminjam" metode objek lain:

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'

Metode calldan applyobjek fungsi (dalam JavaScript, fungsi juga objek) memungkinkan Anda melakukan ini. Jadi, dalam kode Anda, Anda bisa mengatakan bahwa NodeList meminjam metode slice array. .slice()mengembalikan array lain sebagai hasilnya, yang akan menjadi array "dikonversi" yang kemudian dapat Anda gunakan.

Slebetman
sumber
Bang 🎯 penjelasan konsep abstrak untuk fungsi objek javascript. Sekarang, Anda dapat menerapkannya untuk callfungsi Array.prototypealias [].prototypediri Anda sendiri.
Sourabh
29

Ini mengambil slicefungsi dari Array. Ini kemudian memanggil fungsi itu, tetapi menggunakan hasil document.querySelectorAllsebagai thisobjek bukan array yang sebenarnya.

Brian Campbell
sumber
19

Ini adalah teknik untuk mengkonversi objek mirip array ke array nyata.

Beberapa objek ini termasuk:

  • arguments dalam fungsi
  • NodeList (ingat konten mereka dapat berubah setelah diambil! Jadi mengonversinya ke array adalah cara untuk membekukannya)
  • koleksi jQuery, alias objek jQuery (beberapa dokumen: API , ketik , pelajari )

Ini melayani banyak tujuan, misalnya objek dilewatkan dengan referensi sedangkan array dilewatkan oleh nilai.

Perhatikan juga argumen pertama 0bisa dihilangkan, penjelasan menyeluruh di sini .

Dan demi kelengkapan, ada juga jQuery.makeArray () .

Gras Double
sumber
15

Bagaimana cara mengonversi document.querySelectorAll('a')dari a NodeList ke array biasa?

Ini adalah kode yang kami miliki,

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

Mari kita bongkar dulu,

  []    // 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'

Langkah: 1 Eksekusi callfungsi

  • Di dalam call, selain dari thisArg, sisa argumen akan ditambahkan ke daftar argumen.
  • Sekarang fungsi sliceakan dipanggil dengan mengikat thisnilainya sebagai thisArg(array seperti objek berasal document.querySelector) dan dengan daftar argumen. yaitu] argumen startyang berisi0

Langkah: 2 Eksekusi slicefungsi dipanggil dalamcall

  • startakan ditugaskan ke variabel ssebagai0
  • karena endini undefined, this.lengthakan disimpan die
  • sebuah array kosong akan disimpan dalam sebuah variabel a
  • Setelah membuat pengaturan di atas, iterasi berikut akan terjadi

    while(s < e) {
      a.push(this[s]);
      s++;
    }
  • array yang terisi aakan dikembalikan sebagai hasilnya.

PS Untuk memahami skenario kami dengan lebih baik, beberapa langkah yang diperlukan untuk konteks kami telah diabaikan dari algoritme panggilan dan slice yang asli .

Rajaprabhu Aravindasamy
sumber
1
Penjelasan langkah demi langkah yang sangat bagus. Luar biasa! Terima kasih :)
kittu
1
Penjelasan Bagus.
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>
Ankit Parmar
sumber
4

Dari ES6: Cukup buat array dengan Array.from (element.children) atau Array.from ({length: 5})

Мони
sumber