Array menyediakan banyak metode. Untuk mempermudahnya, dalam bab ini mereka dibagi menjadi beberapa kelompok.
Kita sudah mengetahui metode yang menambah dan menghapus item dari awal atau akhir:
arr.push(...items)
– menambahkan item di akhir,
arr.pop()
– mengekstrak item dari akhir,
arr.shift()
– mengekstrak item dari awal,
arr.unshift(...items)
– menambahkan item ke awal.
Berikut beberapa lainnya.
Bagaimana cara menghapus elemen dari array?
Array adalah objek, jadi kita bisa mencoba menggunakan delete
:
let arr = ["Saya", "pergi", "pulang"]; hapus arr[1]; // hapus "pergi" waspada( arr[1] ); // belum diartikan // sekarang arr = ["Saya", , "rumah"]; waspada( arr.panjang ); // 3
Elemen telah dihapus, tetapi array masih memiliki 3 elemen, kita dapat melihat bahwa arr.length == 3
.
Itu wajar, karena delete obj.key
menghapus nilai dengan key
. Hanya itu yang dilakukannya. Baik untuk objek. Namun untuk array, kita biasanya ingin elemen lainnya bergeser dan menempati ruang kosong. Kami berharap memiliki array yang lebih pendek sekarang.
Jadi, metode khusus harus digunakan.
Metode arr.splice adalah pisau Swiss Army untuk array. Ia dapat melakukan segalanya: menyisipkan, menghapus, dan mengganti elemen.
Sintaksnya adalah:
arr.splice(mulai[, deleteCount, elem1, ..., elemN])
Ini memodifikasi arr
mulai dari indeks start
: menghapus elemen deleteCount
dan kemudian menyisipkan elem1, ..., elemN
di tempatnya. Mengembalikan array elemen yang dihapus.
Metode ini mudah dipahami dengan contoh.
Mari kita mulai dengan penghapusan:
let arr = ["Saya", "belajar", "JavaScript"]; arr.sambungan(1, 1); // dari indeks 1 hapus 1 elemen waspada( arr ); //["Saya", "JavaScript"]
Mudah, bukan? Mulai dari indeks 1
dihapus 1
elemen.
Pada contoh berikutnya, kita menghapus 3 elemen dan menggantinya dengan dua elemen lainnya:
let arr = ["Saya", "belajar", "JavaScript", "kanan", "sekarang"]; // hapus 3 elemen pertama dan ganti dengan yang lain arr.splice(0, 3, "Ayo", "menari"); alert( arr ) // sekarang ["Ayo", "menari", "kanan", "sekarang"]
Di sini kita dapat melihat bahwa splice
mengembalikan array elemen yang dihapus:
let arr = ["Saya", "belajar", "JavaScript", "kanan", "sekarang"]; // hapus 2 elemen pertama biarkan dihapus = arr.splice(0, 2); waspada(dihapus); // "I", "study" <-- array elemen yang dihapus
Metode splice
juga mampu menyisipkan elemen tanpa ada kepindahan. Untuk itu, kita perlu menyetel deleteCount
ke 0
:
let arr = ["Saya", "belajar", "JavaScript"]; // dari indeks 2 // hapus 0 // lalu masukkan "kompleks" dan "bahasa" arr.splice(2, 0, "kompleks", "bahasa"); waspada( arr ); // "Saya", "belajar", "kompleks", "bahasa", "JavaScript"
Indeks negatif diperbolehkan
Di sini dan dalam metode array lainnya, indeks negatif diperbolehkan. Mereka menentukan posisi dari akhir array, seperti di sini:
misalkan arr = [1, 2, 5]; // dari indeks -1 (satu langkah dari akhir) // hapus 0 elemen, // lalu masukkan 3 dan 4 arr.sambungan(-1, 0, 3, 4); waspada( arr ); // 1,2,3,4,5
Metode arr.slice jauh lebih sederhana daripada arr.splice
yang tampak serupa.
Sintaksnya adalah:
arr.slice([mulai], [akhir])
Ia mengembalikan array baru yang menyalin semua item dari indeks start
hingga end
(tidak termasuk end
). start
dan end
dapat bernilai negatif, dalam hal ini posisi dari akhir array diasumsikan.
Ini mirip dengan metode string str.slice
, tetapi alih-alih membuat substring, metode ini membuat subarray.
Misalnya:
misalkan arr = ["t", "e", "s", "t"]; waspada( arr.slice(1, 3) ); // e,s (salin dari 1 hingga 3) waspada( arr.slice(-2) ); // s,t (salin dari -2 sampai akhir)
Kita juga dapat memanggilnya tanpa argumen: arr.slice()
membuat salinan arr
. Itu sering digunakan untuk mendapatkan salinan untuk transformasi lebih lanjut yang tidak akan mempengaruhi array asli.
Metode arr.concat membuat larik baru yang menyertakan nilai dari larik lain dan item tambahan.
Sintaksnya adalah:
arr.concat(arg1, arg2...)
Ia menerima sejumlah argumen – baik array atau nilai.
Hasilnya adalah array baru yang berisi item dari arr
, lalu arg1
, arg2
dll.
Jika argumen argN
adalah array, maka semua elemennya akan disalin. Jika tidak, argumen itu sendiri akan disalin.
Misalnya:
misalkan arr = [1, 2]; // membuat array dari: arr dan [3,4] waspada( arr.concat([3, 4]) ); // 1,2,3,4 // membuat array dari: arr dan [3,4] dan [5,6] peringatan( arr.concat([3, 4], [5, 6]) ); // 1,2,3,4,5,6 // buat array dari: arr dan [3,4], lalu tambahkan nilai 5 dan 6 waspada( arr.concat([3, 4], 5, 6) ); // 1,2,3,4,5,6
Biasanya, ini hanya menyalin elemen dari array. Objek lain, meskipun terlihat seperti array, ditambahkan secara keseluruhan:
misalkan arr = [1, 2]; biarkan arraySuka = { 0: "sesuatu", panjang: 1 }; waspada( arr.concat(arrayLike) ); // 1,2,[Objek Objek]
…Tetapi jika objek mirip array memiliki properti khusus Symbol.isConcatSpreadable
, maka objek tersebut diperlakukan sebagai array dengan concat
: sebagai gantinya, elemen-elemennya ditambahkan:
misalkan arr = [1, 2]; biarkan arraySuka = { 0: "sesuatu", 1: "lainnya", [Symbol.isConcatSpreadable]: benar, panjang: 2 }; waspada( arr.concat(arrayLike) ); // 1,2, sesuatu, yang lain
Metode arr.forEach memungkinkan untuk menjalankan fungsi untuk setiap elemen array.
Sintaksnya:
arr.forEach(fungsi(item, indeks, array) { // ...melakukan sesuatu dengan suatu item });
Misalnya, ini menunjukkan setiap elemen array:
// untuk setiap peringatan panggilan elemen ["Bilbo", "Gandalf", "Nazgul"].forEach(waspada);
Dan kode ini lebih menguraikan posisinya dalam array target:
["Bilbo", "Gandalf", "Nazgul"].forEach((item, indeks, array) => { alert(`${item} ada di indeks ${index} di ${array}`); });
Hasil dari fungsi tersebut (jika mengembalikan apa pun) dibuang dan diabaikan.
Sekarang mari kita bahas metode pencarian dalam array.
Metode arr.indexOf dan arr.includes memiliki sintaksis serupa dan pada dasarnya melakukan hal yang sama seperti string, namun beroperasi pada item, bukan karakter:
arr.indexOf(item, from)
– mencari item
mulai dari indeks from
, dan mengembalikan indeks tempat ditemukannya, jika tidak -1
.
arr.includes(item, from)
– mencari item
mulai dari indeks from
, mengembalikan true
jika ditemukan.
Biasanya, metode ini digunakan hanya dengan satu argumen: item
yang akan dicari. Secara default, pencarian dilakukan dari awal.
Misalnya:
biarkan arr = [1, 0, salah]; peringatan( arr.indexOf(0) ); // 1 waspada( arr.indexOf(false) ); // 2 peringatan( arr.indexOf(null) ); // -1 peringatan( arr.termasuk(1) ); // BENAR
Harap perhatikan bahwa indexOf
menggunakan persamaan ketat ===
untuk perbandingan. Jadi, jika kita mencari false
, ia akan menemukan false
dan bukan nol.
Jika kita ingin memeriksa apakah item
ada dalam array dan tidak memerlukan indeks, maka arr.includes
lebih disukai.
Cara arr.lastIndexOf sama dengan indexOf
, namun mencarinya dari kanan ke kiri.
biarkan buah = ['Apel', 'Jeruk', 'Apel'] waspada( buah-buahan.indexOf('Apple') ); // 0 (Apple pertama) peringatan( buah-buahan.lastIndexOf('Apple') ); // 2 (Apple terakhir)
Metode includes
menangani NaN
dengan benar
Fitur minor namun penting dari includes
adalah bahwa ia menangani NaN
dengan benar, tidak seperti indexOf
:
const arr = [NaN]; peringatan( arr.indexOf(NaN) ); // -1 (salah, seharusnya 0) waspada( arr.includes(NaN) );// benar (benar)
Itu karena includes
ditambahkan ke JavaScript jauh di kemudian hari dan menggunakan algoritma perbandingan yang lebih mutakhir secara internal.
Bayangkan kita memiliki serangkaian objek. Bagaimana cara kita menemukan suatu benda dengan kondisi tertentu?
Di sini metode arr.find(fn) berguna.
Sintaksnya adalah:
biarkan hasil = arr.find(fungsi(item, indeks, array) { // jika nilai true dikembalikan, item dikembalikan dan iterasi dihentikan // untuk skenario palsu, hasilnya tidak terdefinisi });
Fungsi ini dipanggil untuk elemen array, satu demi satu:
item
adalah elemennya.
index
adalah indeksnya.
array
adalah array itu sendiri.
Jika mengembalikan true
, pencarian dihentikan, item
dikembalikan. Jika tidak ada yang ditemukan, undefined
dikembalikan.
Misalnya, kita mempunyai array pengguna, masing-masing dengan bidang id
dan name
. Mari kita cari yang memiliki id == 1
:
biarkan pengguna = [ {id: 1, nama: "John"}, {id: 2, nama: "Pete"}, {id: 3, nama: "Maria"} ]; biarkan pengguna = pengguna.find(item => item.id == 1); alert(nama pengguna); // Yohanes
Dalam kehidupan nyata, array objek adalah hal yang umum, sehingga metode find
sangat berguna.
Perhatikan bahwa dalam contoh yang kami berikan untuk find
fungsi item => item.id == 1
dengan satu argumen. Itu tipikal, argumen lain dari fungsi ini jarang digunakan.
Metode arr.findIndex memiliki sintaks yang sama tetapi mengembalikan indeks tempat elemen ditemukan, bukan elemen itu sendiri. Nilai -1
dikembalikan jika tidak ada yang ditemukan.
Metode arr.findLastIndex mirip dengan findIndex
, tetapi mencari dari kanan ke kiri, mirip dengan lastIndexOf
.
Berikut ini contohnya:
biarkan pengguna = [ {id: 1, nama: "John"}, {id: 2, nama: "Pete"}, {id: 3, nama: "Maria"}, {id: 4, nama: "John"} ]; // Temukan indeks John pertama alert(users.findIndex(pengguna => pengguna.nama == 'John')); // 0 // Temukan indeks John terakhir alert(users.findLastIndex(pengguna => nama pengguna == 'John')); // 3
Metode find
mencari satu elemen (pertama) yang membuat fungsi kembali true
.
Kalau boleh banyak, kita bisa menggunakan arr.filter(fn).
Sintaksnya mirip dengan find
, tetapi filter
mengembalikan array berisi semua elemen yang cocok:
biarkan hasil = arr.filter(fungsi(item, indeks, array) { // jika item yang sebenarnya dimasukkan ke hasil dan iterasi berlanjut // mengembalikan array kosong jika tidak ada yang ditemukan });
Misalnya:
biarkan pengguna = [ {id: 1, nama: "John"}, {id: 2, nama: "Pete"}, {id: 3, nama: "Maria"} ]; // mengembalikan array dari dua pengguna pertama biarkan someUsers = pengguna.filter(item => item.id < 3); alert(someUsers.length); // 2
Mari beralih ke metode yang mengubah dan menyusun ulang array.
Metode arr.map adalah salah satu metode yang paling berguna dan sering digunakan.
Ini memanggil fungsi untuk setiap elemen array dan mengembalikan array hasil.
Sintaksnya adalah:
biarkan hasil = arr.map(fungsi(item, indeks, array) { // mengembalikan nilai baru, bukan item });
Misalnya, di sini kita mengubah setiap elemen menjadi panjangnya:
let lengths = ["Bilbo", "Gandalf", "Nazgul"].map(item => item.length); peringatan(panjang); // 5,7,6
Panggilan ke arr.sort() mengurutkan array di tempatnya , mengubah urutan elemennya.
Ini juga mengembalikan array yang diurutkan, tetapi nilai yang dikembalikan biasanya diabaikan, karena arr
sendiri telah dimodifikasi.
Misalnya:
misalkan arr = [ 1, 2, 15 ]; // metode menyusun ulang konten arr arr.sort(); waspada( arr ); // 1, 15, 2
Apakah Anda melihat sesuatu yang aneh pada hasilnya?
Urutannya menjadi 1, 15, 2
. Salah. Tapi kenapa?
Item diurutkan berdasarkan string secara default.
Secara harfiah, semua elemen diubah menjadi string untuk perbandingan. Untuk string, pengurutan leksikografis diterapkan dan memang "2" > "15"
.
Untuk menggunakan urutan pengurutan kita sendiri, kita perlu menyediakan fungsi sebagai argumen arr.sort()
.
Fungsi tersebut harus membandingkan dua nilai arbitrer dan mengembalikan:
fungsi bandingkan(a, b) { jika (a > b) kembalikan 1; // jika nilai pertama lebih besar dari nilai kedua jika (a == b) mengembalikan 0; // jika nilainya sama jika (a < b) mengembalikan -1; // jika nilai pertama lebih kecil dari nilai kedua }
Misalnya, untuk mengurutkan berdasarkan angka:
fungsi bandingkanNumerik(a, b) { jika (a > b) kembalikan 1; jika (a == b) mengembalikan 0; jika (a < b) mengembalikan -1; } misalkan arr = [ 1, 2, 15 ]; arr.sort(bandingkanNumerik); peringatan(arr); // 1, 2, 15
Sekarang berfungsi sebagaimana mestinya.
Mari kita minggir dan memikirkan apa yang terjadi. arr
bisa berupa array apa saja, bukan? Ini mungkin berisi angka atau string atau objek atau apa pun. Kami memiliki satu set beberapa item . Untuk mengurutkannya, kita memerlukan fungsi pemesanan yang mengetahui cara membandingkan elemen-elemennya. Standarnya adalah urutan string.
Metode arr.sort(fn)
mengimplementasikan algoritma pengurutan umum. Kita tidak perlu peduli bagaimana cara kerjanya secara internal (sebagian besar waktu adalah quicksort yang dioptimalkan atau Timsort). Ia akan menjalankan array, membandingkan elemen-elemennya menggunakan fungsi yang disediakan dan menyusun ulang mereka, yang kita perlukan hanyalah menyediakan fn
yang melakukan perbandingan.
Ngomong-ngomong, jika kita ingin mengetahui elemen mana yang dibandingkan – tidak ada yang menghalangi kita untuk memperingatkan mereka:
[1, -2, 15, 2, 0, 8].sort(fungsi(a, b) { peringatan( a + " <> " + b ); kembalikan a - b; });
Algoritme mungkin membandingkan suatu elemen dengan beberapa elemen lain dalam prosesnya, namun ia mencoba membuat perbandingan sesedikit mungkin.
Fungsi perbandingan dapat mengembalikan angka berapa pun
Sebenarnya, fungsi perbandingan hanya diperlukan untuk mengembalikan bilangan positif untuk menyatakan “lebih besar” dan bilangan negatif untuk menyatakan “lebih kecil”.
Itu memungkinkan untuk menulis fungsi yang lebih pendek:
misalkan arr = [ 1, 2, 15 ]; arr.sort(fungsi(a, b) { kembalikan a - b; }); peringatan(arr); // 1, 2, 15
Fungsi panah untuk yang terbaik
Ingat fungsi panah? Kita dapat menggunakannya di sini untuk penyortiran yang lebih rapi:
arr.sort( (a, b) => a - b );
Ini berfungsi persis sama dengan versi yang lebih panjang di atas.
Gunakan localeCompare
untuk string
Ingat algoritma perbandingan string? Ini membandingkan huruf berdasarkan kodenya secara default.
Untuk banyak alfabet, lebih baik menggunakan metode str.localeCompare
untuk mengurutkan huruf dengan benar, seperti Ö
.
Misalnya, mari kita urutkan beberapa negara dalam bahasa Jerman:
biarkan negara = ['Österreich', 'Andorra', 'Vietnam']; alert( negara.sort( (a, b) => a > b ? 1 : -1) ); // Andorra, Vietnam, Österreich (salah) peringatan( negara.sort( (a, b) => a.localeCompare(b) ) ); // Andorra,Österreich, Vietnam (benar!)
Metode arr.reverse membalikkan urutan elemen dalam arr
.
Misalnya:
misalkan arr = [1, 2, 3, 4, 5]; arr.reverse(); waspada( arr ); // 5,4,3,2,1
Itu juga mengembalikan array arr
setelah pembalikan.
Inilah situasi dari kehidupan nyata. Kami sedang menulis aplikasi perpesanan, dan orang tersebut memasukkan daftar penerima yang dipisahkan koma: John, Pete, Mary
. Namun bagi kami, serangkaian nama akan jauh lebih nyaman daripada satu string. Bagaimana cara mendapatkannya?
Metode str.split(delim) melakukan hal itu. Ini membagi string menjadi array dengan pembatas yang diberikan delim
.
Pada contoh di bawah, kami memisahkannya dengan koma diikuti spasi:
biarkan nama = 'Bilbo, Gandalf, Nazgul'; biarkan arr = nama.split(', '); untuk (biarkan nama arr) { alert( `Pesan ke ${nama}.` ); // Pesan untuk Bilbo (dan nama lainnya) }
Metode split
memiliki argumen numerik kedua opsional – batasan panjang array. Jika disediakan, maka elemen tambahan akan diabaikan. Namun dalam praktiknya jarang digunakan:
let arr = 'Bilbo, Gandalf, Nazgul, Saruman'.split(', ', 2); peringatan(arr); // Bilbo, Gandalf
Bagi menjadi huruf
Panggilan ke split(s)
dengan s
kosong akan membagi string menjadi serangkaian huruf:
biarkan str = "uji"; waspada( str.split('') ); // tes
Panggilan arr.join(glue) melakukan kebalikannya ke split
. Ini menciptakan serangkaian item arr
yang disatukan dengan glue
di antara mereka.
Misalnya:
biarkan arr = ['Bilbo', 'Gandalf', 'Nazgul']; biarkan str = arr.join(';'); // rekatkan array menjadi string menggunakan ; peringatan(str); // Bilbo;Gandalf;Nazgul
Saat kita perlu melakukan iterasi pada array – kita dapat menggunakan forEach
, for
atau for..of
.
Saat kita perlu mengulangi dan mengembalikan data untuk setiap elemen – kita dapat menggunakan map
.
Metode arr.reduce dan arr.reduceRight juga termasuk dalam jenis tersebut, namun sedikit lebih rumit. Mereka digunakan untuk menghitung nilai tunggal berdasarkan array.
Sintaksnya adalah:
biarkan nilai = arr.reduce(fungsi(akumulator, item, indeks, array) { // ... }, [awal]);
Fungsi ini diterapkan ke semua elemen array satu demi satu dan “melanjutkan” hasilnya ke panggilan berikutnya.
Argumen:
accumulator
– adalah hasil pemanggilan fungsi sebelumnya, sama dengan initial
pertama kali (jika initial
disediakan).
item
– adalah item array saat ini.
index
– adalah posisinya.
array
– adalah larik.
Saat fungsi diterapkan, hasil pemanggilan fungsi sebelumnya diteruskan ke fungsi berikutnya sebagai argumen pertama.
Jadi, argumen pertama pada dasarnya adalah akumulator yang menyimpan hasil gabungan dari semua eksekusi sebelumnya. Dan pada akhirnya menjadi hasil reduce
.
Kedengarannya rumit?
Cara termudah untuk memahaminya adalah dengan memberi contoh.
Di sini kita mendapatkan jumlah array dalam satu baris:
misalkan arr = [1, 2, 3, 4, 5]; biarkan hasil = arr.reduce((jumlah, arus) => jumlah + arus, 0); peringatan(hasil); // 15
Fungsi yang diteruskan ke reduce
hanya menggunakan 2 argumen, biasanya itu sudah cukup.
Mari kita lihat detail apa yang terjadi.
Saat dijalankan pertama kali, sum
adalah nilai initial
(argumen terakhir dari reduce
), sama dengan 0
, dan current
adalah elemen array pertama, sama dengan 1
. Jadi hasil fungsinya adalah 1
.
Pada proses kedua, sum = 1
, kita menambahkan elemen array kedua ( 2
) ke dalamnya dan kembali.
Pada proses ke-3, sum = 3
dan kita menambahkan satu elemen lagi ke dalamnya, dan seterusnya…
Alur perhitungannya:
Atau dalam bentuk tabel, dimana setiap baris mewakili pemanggilan fungsi pada elemen array berikutnya:
sum | current | hasil | |
---|---|---|---|
panggilan pertama | 0 | 1 | 1 |
panggilan kedua | 1 | 2 | 3 |
panggilan ketiga | 3 | 3 | 6 |
panggilan keempat | 6 | 4 | 10 |
panggilan kelima | 10 | 5 | 15 |
Di sini kita dapat melihat dengan jelas bagaimana hasil dari panggilan sebelumnya menjadi argumen pertama dari panggilan berikutnya.
Kami juga dapat menghilangkan nilai awal:
misalkan arr = [1, 2, 3, 4, 5]; // menghapus nilai awal dari pengurangan (tidak ada 0) biarkan hasil = arr.reduce((jumlah, arus) => jumlah + arus); peringatan(hasil); // 15
Hasilnya sama. Itu karena jika tidak ada inisial, maka reduce
mengambil elemen pertama array sebagai nilai awal dan memulai iterasi dari elemen ke-2.
Tabel perhitungannya sama seperti di atas, dikurangi baris pertama.
Namun penggunaan seperti itu membutuhkan kehati-hatian yang ekstrim. Jika array kosong, maka reduce
panggilan tanpa nilai awal akan menghasilkan kesalahan.
Berikut ini contohnya:
biarkan arr = []; // Error: Pengurangan array kosong tanpa nilai awal // jika nilai awal ada, pengurangan akan mengembalikannya untuk arr yang kosong. arr.reduce((jumlah, arus) => jumlah + arus);
Jadi disarankan untuk selalu menentukan nilai awal.
Metode arr.reduceRight melakukan hal yang sama tetapi bergerak dari kanan ke kiri.
Array tidak membentuk tipe bahasa terpisah. Mereka didasarkan pada objek.
Jadi typeof
tidak membantu membedakan objek biasa dari array:
peringatan(tipe {}); // objek peringatan(tipe []); // objek (sama)
…Tetapi array sangat sering digunakan sehingga ada metode khusus untuk itu: Array.isArray(value). Ia mengembalikan true
jika value
adalah array, dan false
jika sebaliknya.
peringatan(Array.isArray({})); // PALSU peringatan(Array.isArray([])); // BENAR
Hampir semua metode array yang memanggil fungsi – seperti find
, filter
, map
, dengan pengecualian sort
, menerima parameter tambahan opsional thisArg
.
Parameter tersebut tidak dijelaskan pada bagian di atas, karena jarang digunakan. Tapi untuk kelengkapannya, kita harus menutupinya.
Berikut sintaks lengkap dari metode ini:
arr.find(func, thisArg); arr.filter(fungsi, thisArg); arr.peta(fungsi, thisArg); // ... // thisArg adalah argumen opsional terakhir
Nilai parameter thisArg
menjadi this
untuk func
.
Misalnya, di sini kita menggunakan metode objek army
sebagai filter, dan thisArg
meneruskan konteksnya:
biarkan tentara = { umur minimal: 18, usia maks: 27, dapatBergabung(pengguna) { kembalikan pengguna.usia >= ini.minAge && pengguna.usia < ini.maxAge; } }; biarkan pengguna = [ {usia: 16}, {usia: 20}, {usia: 23}, {usia: 30} ]; // temukan pengguna, untuk siapa army.canJoin mengembalikan nilai true biarkan tentara = pengguna.filter(tentara.canJoin, tentara); alert(tentara.panjang); // 2 alert(tentara[0].usia); // 20 alert(tentara[1].usia); // 23
Jika pada contoh di atas kita menggunakan users.filter(army.canJoin)
, maka army.canJoin
akan dipanggil sebagai fungsi mandiri, dengan this=undefined
, sehingga menyebabkan kesalahan instan.
Panggilan ke users.filter(army.canJoin, army)
dapat diganti dengan users.filter(user => army.canJoin(user))
, yang melakukan hal yang sama. Yang terakhir ini lebih sering digunakan, karena lebih mudah dipahami oleh kebanyakan orang.
Lembar contekan metode array:
Untuk menambah/menghapus elemen:
push(...items)
– menambahkan item di akhir,
pop()
– mengekstrak item dari akhir,
shift()
– mengekstrak item dari awal,
unshift(...items)
– menambahkan item ke awal.
splice(pos, deleteCount, ...items)
– di indeks pos
menghapus elemen deleteCount
dan menyisipkan items
.
slice(start, end)
– membuat array baru, menyalin elemen dari indeks start
hingga end
(tidak inklusif) ke dalamnya.
concat(...items)
– mengembalikan array baru: menyalin semua anggota array saat ini dan menambahkan items
ke dalamnya. Jika salah satu items
adalah array, maka elemennya akan diambil.
Untuk mencari di antara elemen:
indexOf/lastIndexOf(item, pos)
– mencari item
mulai dari posisi pos
, dan mengembalikan indeks atau -1
jika tidak ditemukan.
includes(value)
– mengembalikan true
jika array memiliki value
, jika tidak, false
.
find/filter(func)
– memfilter elemen melalui fungsi, mengembalikan nilai pertama/semua yang membuatnya mengembalikan true
.
findIndex
sama seperti find
, tetapi mengembalikan indeks, bukan nilai.
Untuk mengulangi elemen:
forEach(func)
– memanggil func
untuk setiap elemen, tidak mengembalikan apa pun.
Untuk mengubah array:
map(func)
– membuat array baru dari hasil pemanggilan func
untuk setiap elemen.
sort(func)
– mengurutkan array di tempatnya, lalu mengembalikannya.
reverse()
– membalikkan array pada tempatnya, lalu mengembalikannya.
split/join
– mengonversi string menjadi array dan sebaliknya.
reduce/reduceRight(func, initial)
– menghitung nilai tunggal pada array dengan memanggil func
untuk setiap elemen dan meneruskan hasil antara di antara panggilan tersebut.
Selain itu:
Array.isArray(value)
memeriksa value
untuk menjadi array, jika demikian mengembalikan true
, jika tidak false
.
Harap dicatat bahwa metode sort
, reverse
dan splice
memodifikasi array itu sendiri.
Metode ini adalah yang paling banyak digunakan, mencakup 99% kasus penggunaan. Namun ada beberapa lainnya:
arr.some(fn)/arr.every(fn) periksa arraynya.
Fungsi fn
dipanggil pada setiap elemen array mirip dengan map
. Jika salah satu/semua hasil adalah true
, kembalikan true
, jika tidak false
.
Metode ini berperilaku seperti ||
dan &&
operator: jika fn
mengembalikan nilai yang sebenarnya, arr.some()
segera mengembalikan true
dan berhenti mengulangi item lainnya; jika fn
mengembalikan nilai yang salah, arr.every()
segera mengembalikan false
dan berhenti melakukan iterasi pada item lainnya juga.
Kita dapat menggunakan every
untuk membandingkan array:
fungsi arraysEqual(arr1, arr2) { return arr1.length === arr2.length && arr1.every((nilai, indeks) => nilai === arr2[index]); } peringatan( arrayEqual([1, 2], [1, 2])); // BENAR
arr.fill(value, start, end) – mengisi array dengan value
berulang dari indeks start
hingga end
.
arr.copyWithin(target, start, end) – menyalin elemen-elemennya dari posisi start
hingga posisi end
ke dirinya sendiri , pada posisi target
(menimpa yang sudah ada).
arr.flat(kedalaman)/arr.flatMap(fn) membuat array datar baru dari array multidimensi.
Untuk daftar lengkapnya, lihat manualnya.
Pada pandangan pertama, tampaknya ada begitu banyak metode yang cukup sulit untuk diingat. Namun sebenarnya, itu jauh lebih mudah.
Lihatlah lembar contekan hanya untuk menyadarinya. Kemudian selesaikan tugas-tugas bab ini untuk berlatih, sehingga Anda memiliki pengalaman dengan metode array.
Setelah itu, kapan pun Anda perlu melakukan sesuatu dengan array, dan Anda tidak tahu caranya – datang ke sini, lihat lembar contekan dan temukan metode yang tepat. Contoh akan membantu Anda menulisnya dengan benar. Anda akan segera mengingat metodenya, tanpa upaya khusus dari pihak Anda.
pentingnya: 5
Tulis fungsi camelize(str)
yang mengubah kata-kata yang dipisahkan tanda hubung seperti “my-short-string” menjadi “myShortString” yang menggunakan huruf unta.
Yaitu: menghilangkan semua tanda hubung, setiap kata setelah tanda hubung menjadi huruf besar.
Contoh:
camelize("warna latar") == 'warna latar'; camelize("daftar-gaya-gambar") == 'listStyleImage'; camelize("-webkit-transition") == 'WebkitTransition';
Petunjuk PS: gunakan split
untuk membagi string menjadi sebuah array, ubah dan join
kembali.
Buka kotak pasir dengan tes.
fungsi unta(str) { kembali str .split('-') // membagi 'kata-panjang-saya' menjadi array ['kata-saya', 'panjang', 'kata'] .peta( // menggunakan huruf besar pada huruf pertama semua item array kecuali yang pertama // mengubah ['saya', 'panjang', 'kata'] menjadi ['saya', 'Panjang', 'Kata'] (kata, indeks) => indeks == 0 ? kata : kata[0].toUpperCase() + kata.slice(1) ) .bergabung(''); // menggabungkan ['my', 'Long', 'Word'] ke dalam 'myLongWord' }
Buka solusi dengan pengujian di kotak pasir.
pentingnya: 4
Tulis fungsi filterRange(arr, a, b)
yang mendapatkan array arr
, mencari elemen dengan nilai lebih tinggi atau sama dengan a
dan lebih rendah atau sama dengan b
dan mengembalikan hasilnya sebagai array.
Fungsi tersebut tidak boleh mengubah array. Itu harus mengembalikan array baru.
Misalnya:
misalkan arr = [5, 3, 8, 1]; biarkan difilter = filterRange(arr, 1, 4); peringatan( disaring ); // 3,1 (nilai yang cocok) waspada( arr ); // 5,3,8,1 (tidak diubah)
Buka kotak pasir dengan tes.
fungsi filterRange(arr, a, b) { // menambahkan tanda kurung di sekitar ekspresi agar lebih mudah dibaca return arr.filter(item => (a <= item && item <= b)); } misalkan arr = [5, 3, 8, 1]; biarkan difilter = filterRange(arr, 1, 4); peringatan( disaring ); // 3,1 (nilai yang cocok) waspada( arr ); // 5,3,8,1 (tidak diubah)
Buka solusi dengan pengujian di kotak pasir.
pentingnya: 4
Tulis fungsi filterRangeInPlace(arr, a, b)
yang mendapatkan array arr
dan menghapus semua nilai kecuali nilai yang berada di antara a
dan b
. Tesnya adalah: a ≤ arr[i] ≤ b
.
Fungsi tersebut seharusnya hanya mengubah array. Seharusnya tidak mengembalikan apa pun.
Misalnya:
misalkan arr = [5, 3, 8, 1]; filterRangeInPlace(arr, 1, 4); // menghapus angka kecuali dari 1 sampai 4 waspada( arr ); // [3, 1]
Buka kotak pasir dengan tes.
fungsi filterRangeInPlace(arr, a, b) { for (misalkan i = 0; i < arr.length; i++) { misalkan val = arr[i]; // hapus jika di luar interval jika (val < a || val > b) { arr.sambungan(i, 1); Saya--; } } } misalkan arr = [5, 3, 8, 1]; filterRangeInPlace(arr, 1, 4); // menghapus angka kecuali dari 1 sampai 4 waspada( arr ); // [3, 1]
Buka solusi dengan pengujian di kotak pasir.
pentingnya: 4
misalkan arr = [5, 2, 1, -10, 8]; // ... kode Anda untuk mengurutkannya dalam urutan menurun waspada( arr ); // 8, 5, 2, 1, -10
misalkan arr = [5, 2, 1, -10, 8]; arr.sort((a, b) => b - a); waspada( arr );
pentingnya: 5
Kami memiliki array string arr
. Kami ingin memiliki salinan yang telah diurutkan, tetapi arr
tidak diubah.
Buat fungsi copySorted(arr)
yang mengembalikan salinan tersebut.
biarkan arr = ["HTML", "JavaScript", "CSS"]; biarkan diurutkan = copySorted(arr); peringatan( diurutkan ); // CSS, HTML, Javascript waspada( arr ); // HTML, JavaScript, CSS (tidak ada perubahan)
Kita dapat menggunakan slice()
untuk membuat salinan dan menjalankan pengurutan di dalamnya:
fungsi copySorted(arr) { return arr.slice().sort(); } biarkan arr = ["HTML", "JavaScript", "CSS"]; biarkan diurutkan = copySorted(arr); peringatan( diurutkan ); waspada( arr );
pentingnya: 5
Buat Calculator
fungsi konstruktor yang membuat objek kalkulator "dapat diperluas".
Tugas ini terdiri dari dua bagian.
Pertama, terapkan metode calculate(str)
yang mengambil string seperti "1 + 2"
dalam format “NUMBER operator NUMBER” (dibatasi spasi) dan mengembalikan hasilnya. Harus paham plus +
dan minus -
.
Contoh penggunaan:
biarkan calc = Kalkulator baru; alert( calc.calculate("3 + 7") ); // 10
Kemudian tambahkan metode addMethod(name, func)
yang mengajarkan operasi baru pada kalkulator. Dibutuhkan name
operator dan fungsi dua argumen func(a,b)
yang mengimplementasikannya.
Misalnya, mari kita tambahkan perkalian *
, pembagian /
dan pangkat **
:
biarkan powerCalc = Kalkulator baru; powerCalc.addMethod("*", (a, b) => a * b); powerCalc.addMethod("/", (a, b) => a / b); powerCalc.addMethod("**", (a, b) => a ** b); biarkan hasil = powerCalc.calculate("2**3"); peringatan(hasil); // 8
Tidak ada tanda kurung atau ekspresi kompleks dalam tugas ini.
Angka dan operator dibatasi tepat dengan satu spasi.
Mungkin ada kesalahan penanganan jika Anda ingin menambahkannya.
Buka kotak pasir dengan tes.
Harap perhatikan bagaimana metode disimpan. Mereka hanya ditambahkan ke properti this.methods
.
Semua tes dan konversi numerik dilakukan dalam metode calculate
. Di masa depan, ini mungkin diperluas untuk mendukung ekspresi yang lebih kompleks.
fungsi Kalkulator() { ini.metode = { "-": (a, b) => a - b, "+": (a, b) => a + b }; ini.hitung = fungsi(str) { biarkan terbelah = str.split(' '), a = +belah[0], op = membagi[1], b = +pemisahan[2]; if (!ini.metode[op] || isNaN(a) || isNaN(b)) { kembalikan NaN; } kembalikan ini.metode[op](a, b); }; this.addMethod = fungsi(nama, fungsi) { this.methods[nama] = fungsi; }; }
Buka solusi dengan pengujian di kotak pasir.
pentingnya: 5
Anda memiliki array objek user
, masing-masing memiliki user.name
. Tulis kode yang mengubahnya menjadi array nama.
Misalnya:
misalkan john = { nama: "John", umur: 25 }; let pete = { nama: "Pete", umur: 30 }; misalkan mary = { nama: "Maria", umur: 28 }; biarkan pengguna = [ john, pete, mary ]; biarkan nama = /* ...kode anda */ peringatan( nama ); // John, Pete, Maria
misalkan john = { nama: "John", umur: 25 }; let pete = { nama: "Pete", umur: 30 }; misalkan mary = { nama: "Maria", umur: 28 }; biarkan pengguna = [ john, pete, mary ]; biarkan nama = pengguna.peta(item => item.nama); peringatan( nama ); // John, Pete, Maria
pentingnya: 5
Anda memiliki serangkaian objek user
, masing-masing memiliki name
, surname
, dan id
.
Tulis kode untuk membuat larik lain darinya, objek dengan id
dan fullName
, tempat fullName
dihasilkan dari name
dan surname
.
Misalnya:
let john = { nama: "John", nama keluarga: "Smith", id: 1 }; let pete = { nama: "Pete", nama keluarga: "Berburu", id: 2 }; let mary = { nama: "Mary", nama keluarga: "Kunci", id: 3 }; biarkan pengguna = [ john, pete, mary ]; biarkan penggunaMapped = /* ... kode Anda ... */ /* penggunaDipetakan = [ {Nama Lengkap: "John Smith", ID: 1 }, {Nama lengkap: "Pete Hunt", id: 2 }, {Nama lengkap: "Mary Key", id: 3 } ] */ peringatan( penggunaDipetakan[0].id ) // 1 peringatan( penggunaMapped[0].fullName ) // John Smith
Jadi, sebenarnya Anda perlu memetakan satu array objek ke objek lainnya. Coba gunakan =>
di sini. Ada tangkapan kecil.
let john = { nama: "John", nama keluarga: "Smith", id: 1 }; let pete = { nama: "Pete", nama keluarga: "Berburu", id: 2 }; let mary = { nama: "Mary", nama keluarga: "Kunci", id: 3 }; biarkan pengguna = [ john, pete, mary ]; biarkan penggunaMapped = pengguna.peta(pengguna => ({ Nama lengkap: `${nama.pengguna} ${nama belakang pengguna}`, id: pengguna.id })); /* penggunaDipetakan = [ {Nama Lengkap: "John Smith", ID: 1 }, {Nama lengkap: "Pete Hunt", id: 2 }, {Nama lengkap: "Mary Key", id: 3 } ] */ peringatan( penggunaDipetakan[0].id ); // 1 peringatan( penggunaDipetakan[0].nama lengkap ); // John Smith
Harap dicatat bahwa dalam fungsi panah kita perlu menggunakan tanda kurung tambahan.
Kami tidak bisa menulis seperti ini:
biarkan penggunaMapped = pengguna.peta(pengguna => { Nama lengkap: `${nama.pengguna} ${nama belakang pengguna}`, id: pengguna.id });
Seperti yang kita ingat, ada dua fungsi panah: tanpa body value => expr
dan dengan body value => {...}
.
Di sini JavaScript akan memperlakukan {
sebagai awal dari isi fungsi, bukan awal dari objek. Solusinya adalah dengan membungkusnya dalam tanda kurung “normal”:
biarkan penggunaMapped = pengguna.peta(pengguna => ({ Nama lengkap: `${nama.pengguna} ${nama belakang pengguna}`, id: pengguna.id }));
Sekarang baiklah.
pentingnya: 5
Tulis fungsi sortByAge(users)
yang mendapatkan array objek dengan properti age
dan mengurutkannya berdasarkan age
.
Misalnya:
misalkan john = { nama: "John", umur: 25 }; let pete = { nama: "Pete", umur: 30 }; misalkan mary = { nama: "Maria", umur: 28 }; biarkan arr = [ pete, john, mary ]; sortirBerdasarkanUmur(arr); // sekarang: [john, mary, pete] peringatan(arr[0].nama); // Yohanes peringatan(arr[1].nama); // Maria peringatan(arr[2].nama); // Pete
fungsi sortirBerdasarkanUmur(arr) { arr.sort((a, b) => a.usia - b.usia); } misalkan john = { nama: "John", umur: 25 }; let pete = { nama: "Pete", umur: 30 }; misalkan mary = { nama: "Maria", umur: 28 }; biarkan arr = [ pete, john, mary ]; sortirBerdasarkanUmur(arr); // sekarang yang diurutkan adalah: [john, mary, pete] peringatan(arr[0].nama); // Yohanes peringatan(arr[1].nama); // Maria peringatan(arr[2].nama); // Pete
pentingnya: 3
Tulis fungsi shuffle(array)
yang mengacak (mengurutkan ulang secara acak) elemen array.
Beberapa kali shuffle
dapat menghasilkan urutan elemen yang berbeda. Misalnya:
misalkan arr = [1, 2, 3]; acak(arr); // arr = [3, 2, 1] acak(arr); // arr = [2, 1, 3] acak(arr); // arr = [3, 1, 2] // ...
Semua urutan elemen harus memiliki probabilitas yang sama. Misalnya, [1,2,3]
dapat disusun ulang menjadi [1,2,3]
atau [1,3,2]
atau [3,1,2]
dll, dengan probabilitas yang sama untuk setiap kasus.
Solusi sederhananya adalah:
fungsi acak(array) { array.sort(() => Matematika.acak() - 0,5); } misalkan arr = [1, 2, 3]; shuffle (arr); peringatan (arr);
Itu agak berfungsi, karena Math.random() - 0.5
adalah angka acak yang mungkin positif atau negatif, sehingga fungsi penyortiran merekam kembali elemen secara acak.
Tetapi karena fungsi penyortiran tidak dimaksudkan untuk digunakan dengan cara ini, tidak semua permutasi memiliki probabilitas yang sama.
Misalnya, pertimbangkan kode di bawah ini. Ini menjalankan shuffle
1000000 kali dan menghitung penampilan dari semua hasil yang mungkin:
fungsi shuffle (array) { array.sort (() => math.random () - 0.5); } // Hitungan penampilan untuk semua permutasi yang mungkin Biarkan Count = { '123': 0, '132': 0, '213': 0, '231': 0, '321': 0, '312': 0 }; untuk (biarkan i = 0; i <1000000; i ++) { Biarkan array = [1, 2, 3]; shuffle (array); hitung [array.join ('')] ++; } // tunjukkan jumlah permutasi yang mungkin untuk (biarkan kunci dalam hitungan) { alert (`$ {key}: $ {count [key]}`); }
Contoh hasil (tergantung pada mesin JS):
123: 250706 132: 124425 213: 249618 231: 124880 312: 125148 321: 125223
Kita dapat melihat bias dengan jelas: 123
dan 213
tampak jauh lebih sering daripada yang lain.
Hasil kode dapat bervariasi antara mesin JavaScript, tetapi kita sudah dapat melihat bahwa pendekatannya tidak dapat diandalkan.
Mengapa tidak berhasil? Secara umum, sort
adalah "kotak hitam": kami melempar array dan fungsi perbandingan ke dalamnya dan mengharapkan array akan diurutkan. Tetapi karena keacakan dari perbandingan kotak hitam menjadi gila, dan bagaimana tepatnya menjadi gila tergantung pada implementasi konkret yang berbeda antara mesin.
Ada cara bagus lainnya untuk melakukan tugas itu. Misalnya, ada algoritma hebat yang disebut Fisher-Yates Shuffle. Idenya adalah untuk berjalan di array dalam urutan terbalik dan menukar setiap elemen dengan yang acak sebelumnya:
fungsi shuffle (array) { untuk (biarkan i = array.length-1; i> 0; i--) { Biarkan j = math.floor (math.random () * (i + 1)); // indeks acak dari 0 ke i // SWAP Elements Array [i] dan array [j] // Kami menggunakan sintaks "penugasan perusak" untuk mencapai itu // Anda akan menemukan detail lebih lanjut tentang sintaks itu di bab -bab selanjutnya // Sama dapat ditulis sebagai: // Biarkan t = array [i]; array [i] = array [j]; array [j] = t [array [i], array [j]] = [array [j], array [i]]; } }
Mari kita mengujinya dengan cara yang sama:
fungsi shuffle (array) { untuk (biarkan i = array.length-1; i> 0; i--) { Biarkan j = math.floor (math.random () * (i + 1)); [array [i], array [j]] = [array [j], array [i]]; } } // Hitungan penampilan untuk semua permutasi yang mungkin Biarkan Count = { '123': 0, '132': 0, '213': 0, '231': 0, '321': 0, '312': 0 }; untuk (biarkan i = 0; i <1000000; i ++) { Biarkan array = [1, 2, 3]; shuffle (array); hitung [array.join ('')] ++; } // tunjukkan jumlah permutasi yang mungkin untuk (biarkan kunci dalam hitungan) { alert (`$ {key}: $ {count [key]}`); }
Output contoh:
123: 166693 132: 166647 213: 166628 231: 167517 312: 166199 321: 166316
Terlihat bagus sekarang: Semua permutasi muncul dengan probabilitas yang sama.
Juga, dari segi kinerja algoritma Fisher-Yates jauh lebih baik, tidak ada overhead "menyortir".
Pentingnya: 4
Tulis fungsi getAverageAge(users)
yang mendapatkan berbagai objek dengan age
properti dan mengembalikan usia rata -rata.
Rumus untuk rata -rata adalah (age1 + age2 + ... + ageN) / N
.
Misalnya:
Biarkan John = {name: "John", usia: 25}; Biarkan Pete = {name: "Pete", usia: 30}; Biarkan Mary = {name: "Mary", usia: 29}; Biarkan arr = [John, Pete, Mary]; waspada (getAverageAge (ARR)); // (25 + 30 + 29) / 3 = 28
fungsi getAverageAge (pengguna) { return user.reduce ((prev, user) => prev + user.age, 0) / user.length; } Biarkan John = {name: "John", usia: 25}; Biarkan Pete = {name: "Pete", usia: 30}; Biarkan Mary = {name: "Mary", usia: 29}; Biarkan arr = [John, Pete, Mary]; waspada (getAverageAge (ARR)); // 28
Pentingnya: 4
Biarkan arr
menjadi array.
Buat fungsi unique(arr)
yang seharusnya mengembalikan array dengan item arr
unik.
Misalnya:
fungsi unik (arr) { / * kode Anda */ } Let Strings = ["Hare", "Krishna", "Hare", "Krishna", "Krishna", "Krishna", "Hare", "Hare", ": -O" ]; peringatan (unik (string)); // Hare, Krishna ,: -O
Buka kotak pasir dengan tes.
Ayo jalankan item array:
Untuk setiap item, kami akan memeriksa apakah array yang dihasilkan sudah memiliki item itu.
Jika demikian, maka abaikan, jika tidak tambahkan hasil.
fungsi unik (arr) { Biarkan hasil = []; untuk (biarkan str dari arr) { if (! result.includes (str)) { result.push (str); } } hasil pengembalian; } Let Strings = ["Hare", "Krishna", "Hare", "Krishna", "Krishna", "Krishna", "Hare", "Hare", ": -O" ]; peringatan (unik (string)); // Hare, Krishna ,: -O
Kode berfungsi, tetapi ada masalah kinerja potensial di dalamnya.
Metode result.includes(str)
secara internal berjalan result
array dan membandingkan setiap elemen dengan str
untuk menemukan pertandingan.
Jadi jika ada 100
elemen dalam result
dan tidak ada yang cocok dengan str
, maka itu akan berjalan seluruh result
dan melakukan tepat 100
perbandingan. Dan jika result
besar, seperti 10000
, maka akan ada 10000
perbandingan.
Itu bukan masalah dengan sendirinya, karena mesin JavaScript sangat cepat, jadi berjalan 10000
array adalah masalah mikrodetik.
Tetapi kami melakukan tes seperti itu untuk setiap elemen arr
, di loop for
.
Jadi jika arr.length
adalah 10000
kita akan memiliki sesuatu seperti 10000*10000
= 100 juta perbandingan. Itu banyak.
Jadi solusinya hanya baik untuk array kecil.
Lebih jauh di peta bab dan set kita akan lihat bagaimana mengoptimalkannya.
Buka solusi dengan tes dalam kotak pasir.
Pentingnya: 4
Katakanlah kami menerima array pengguna dalam formulir {id:..., name:..., age:... }
.
Buat fungsi groupById(arr)
yang membuat objek darinya, dengan id
sebagai kunci, dan item array sebagai nilai.
Misalnya:
Biarkan pengguna = [ {id: 'John', nama: "John Smith", usia: 20}, {id: 'ann', nama: "Ann Smith", usia: 24}, {id: 'Pete', nama: "Pete Peterson", usia: 31}, ]; let UsersById = groupById (pengguna); /* // Setelah panggilan yang harus kita miliki: UsersById = { John: {id: 'John', nama: "John Smith", usia: 20}, Ann: {id: 'Ann', nama: "Ann Smith", usia: 24}, Pete: {id: 'Pete', nama: "Pete Peterson", usia: 31}, } */
Fungsi seperti itu sangat berguna saat bekerja dengan data server.
Dalam tugas ini kami berasumsi bahwa id
itu unik. Mungkin tidak ada dua item array dengan id
yang sama.
Harap gunakan array .reduce
metode dalam solusi.
Buka kotak pasir dengan tes.
function groupById (array) { return array.reduce ((obj, value) => { obj [value.id] = value; kembalikan obj; }, {}) }
Buka solusi dengan tes dalam kotak pasir.