Objek `Array`
Artikel ini menerangkan tentang objek Array.
Saya akan menerangkan penggunaan praktikal array langkah demi langkah dengan cara yang mudah difahami.
YouTube Video
Objek Array
Objek Array dalam JavaScript adalah salah satu struktur paling penting yang menjadi asas kepada pelbagai jenis pemprosesan data. Daripada operasi array asas hinggalah fungsi aras tinggi yang berguna untuk transformasi data yang efisien, terdapat banyak ciri yang anda perlu tahu.
Asas Array
Dalam JavaScript, array adalah struktur data asas untuk mengendalikan pelbagai nilai secara serentak. Di sini, kami memperkenalkan cara mencipta array serta cara membaca dan menulis elemen-elemennya dengan contoh-contoh ringkas.
1// Create arrays in different ways
2const arr1 = [1, 2, 3]; // array literal
3const arr2 = new Array(4, 5, 6); // Array constructor
4const arr3 = Array.of(7, 8, 9); // Array.of
5
6console.log("arr1 created with literal. :", arr1);
7console.log("arr2 created with constructor:", arr2);
8console.log("arr3 created with Array.of. :", arr3);
9// arr1 created with literal. : [ 1, 2, 3 ]
10// arr2 created with constructor: [ 4, 5, 6 ]
11// arr3 created with Array.of. : [ 7, 8, 9 ]
12
13// Access and modify elements
14let first = arr1[0]; // read element
15console.log("First element of arr1:", first);
16// First element of arr1: 1
17
18arr1[1] = 20; // modify element
19console.log("arr1 after modifying index 1:", arr1);
20// arr1 after modifying index 1: [ 1, 20, 3 ]
21
22const len = arr1.length; // get length
23console.log("Length of arr1:", len);
24// Length of arr1: 3
- Kod ini menunjukkan tiga cara untuk mencipta array, cara membaca dan mengemaskini elemen menggunakan indeks, dan cara mendapatkan panjang array melalui sifat
length. - Literal tatasusunan adalah yang paling biasa dan mudah dibaca, dan paling kerap digunakan dalam situasi harian.
Menambah dan Membuang Elemen (di Hujung atau Permulaan)
Array membolehkan anda menambah atau membuang elemen dengan mudah di hujung atau permulaan. Operasi ini juga berguna ketika melaksanakan struktur seperti stack atau queue.
1// Push and pop (stack-like)
2const stack = [];
3console.log("Initial stack:", stack);
4
5stack.push(1); // push 1
6console.log("After push(1):", stack);
7
8stack.push(2); // push 2
9console.log("After push(2):", stack);
10
11const last = stack.pop(); // pop -> 2
12console.log("Popped value:", last);
13console.log("Stack after pop():", stack);
14
15// Unshift and shift (queue-like)
16const queue = [];
17console.log("Initial queue:", queue);
18
19queue.push('a'); // add to end
20console.log("After push('a'):", queue);
21
22queue.unshift('start'); // add to front
23console.log("After unshift('start'):", queue);
24
25const firstItem = queue.shift(); // remove from front
26console.log("Shifted value:", firstItem);
27console.log("Queue after shift():", queue);
28
29// Initial stack: []
30// After push(1): [ 1 ]
31// After push(2): [ 1, 2 ]
32// Popped value: 2
33// Stack after pop(): [ 1 ]
34
35// Initial queue: []
36// After push('a'): [ 'a' ]
37// After unshift('start'): [ 'start', 'a' ]
38// Shifted value: start
39// Queue after shift(): [ 'a' ]
pushdanpopberoperasi di hujung array. Ia sangat sesuai untuk melaksanakan struktur stack.unshiftdanshiftberoperasi di permulaan array. Namun, perlu diingat bahawa operasi di permulaan memerlukan penukaran indeks semua elemen secara dalaman, menjadikannya operasi yang berat.
Mengendalikan Elemen di Tengah (splice dan slice)
Apabila mengendalikan elemen di tengah array, pilih antara splice dan slice bergantung kepada sama ada anda ingin mengubah array asal atau tidak. Jika anda hanya mahu mengekstrak sebahagian daripada tatasusunan, gunakan slice; jika anda mahu mengubah tatasusunan itu sendiri, seperti memasukkan atau memadam elemen, gunakan splice.
1// slice (non-destructive)
2const nums = [0, 1, 2, 3, 4];
3console.log("Original nums:", nums);
4
5const part = nums.slice(1, 4); // returns [1, 2, 3]
6console.log("Result of nums.slice(1, 4):", part);
7console.log("nums after slice (unchanged):", nums);
8
9// splice (destructive)
10const arr = [10, 20, 30, 40];
11console.log("\nOriginal arr:", arr);
12
13// remove 1 item at index 2, insert 25 and 27
14arr.splice(2, 1, 25, 27);
15console.log("After arr.splice(2, 1, 25, 27):", arr);
16
17// Original nums: [ 0, 1, 2, 3, 4 ]
18// Result of nums.slice(1, 4): [ 1, 2, 3 ]
19// nums after slice (unchanged): [ 0, 1, 2, 3, 4 ]
20
21// Original arr: [ 10, 20, 30, 40 ]
22// After arr.splice(2, 1, 25, 27): [ 10, 20, 25, 27, 40 ]
slicehanya mengeluarkan elemen dan tidak mengubah array asal.splicemenambah atau membuang elemen serta mengubah array itu sendiri, jadi berhati-hati dengan kesannya terhadap perilaku kod anda.
Lakaran (for / for...of / forEach)
Terdapat beberapa cara untuk memproses array secara berurutan, dan anda boleh memilih mengikut tujuan serta gaya pengkodan anda. Berikut adalah tiga struktur gelung yang tipikal.
1const items = ['apple', 'banana', 'cherry'];
2console.log("Items:", items);
3
4// classic for
5console.log("\n--- Classic for loop ---");
6for (let i = 0; i < items.length; i++) {
7 console.log(`Index: ${i}, Value: ${items[i]}`);
8}
9
10// for...of (recommended for values)
11console.log("\n--- for...of loop ---");
12for (const item of items) {
13 console.log(`Value: ${item}`);
14}
15
16// forEach (functional style)
17console.log("\n--- forEach loop ---");
18items.forEach((item, index) => {
19 console.log(`Index: ${index}, Value: ${item}`);
20});- Gelung
foradalah yang paling fleksibel, membolehkan operasi ke atas indeks serta kawalan terperinci ke atas ulangan menggunakanbreakdan pernyataan lain. for...ofmenyediakan cara yang ringkas untuk mengendalikan nilai elemen dan paling seimbang dari segi kebolehbacaan.forEachmembenarkan penulisan kod gaya fungsian dan sesuai untuk operasi kesan sampingan seperti logging atau mengemaskini data setiap elemen. Namun, perhatikan bahawa anda tidak boleh menggunakanbreakataucontinue, dan ia tidak sesuai untuk pemprosesan asinkron menggunakanawait.
map / filter / reduce — Fungsi Aras Tinggi
map, filter, dan reduce ialah fungsi aras tinggi yang kerap digunakan semasa mengubah, menapis, atau mengagregatkan array. Oleh kerana anda boleh menyatakan proses berulang dengan jelas, kod anda menjadi ringkas dan mudah difahami.
1const numbers = [1, 2, 3, 4, 5];
2console.log("Original numbers:", numbers);
3
4// map: transform each item
5const doubled = numbers.map(n => n * 2);
6console.log("\nResult of map (n * 2):", doubled);
7
8// filter: select items
9const evens = numbers.filter(n => n % 2 === 0);
10console.log("Result of filter (even numbers):", evens);
11
12// reduce: accumulate to single value
13const sum = numbers.reduce((acc, n) => acc + n, 0);
14console.log("Result of reduce (sum):", sum);
15
16// Original numbers: [ 1, 2, 3, 4, 5 ]
17// Result of map (n * 2): [ 2, 4, 6, 8, 10 ]
18// Result of filter (even numbers): [ 2, 4 ]
19// Result of reduce (sum): 15
- Kaedah-kaedah ini membolehkan anda menumpukan kepada apa yang ingin dilakukan dalam gaya deklaratif, meningkatkan kebolehbacaan dan membantu mengelakkan kesan sampingan yang tidak diingini.
find / findIndex / some / every
Berikut adalah ringkasan kaedah pencarian dan pemeriksaan syarat. Kaedah-kaedah ini berguna untuk mencari elemen yang memenuhi syarat tertentu atau melakukan semakan boolean ke atas set.
1const users = [
2 { id: 1, name: 'Alice' },
3 { id: 2, name: 'Bob' },
4 { id: 3, name: 'Carol' }
5];
6
7console.log("Users:", users);
8
9// Find the first user whose name is 'Bob'
10const bob = users.find(user => user.name === 'Bob');
11console.log("\nResult of find (name === 'Bob'):", bob);
12
13// Find index of the user whose id is 3
14const indexOfId3 = users.findIndex(user => user.id === 3);
15console.log("Result of findIndex (id === 3):", indexOfId3);
16
17// Check if there exists a user with id = 2
18const hasId2 = users.some(user => user.id === 2);
19console.log("Result of some (id === 2):", hasId2);
20
21// Check if all users have a numeric id
22const allHaveNumericId = users.every(user => typeof user.id === 'number');
23console.log("Result of every (id is number):", allHaveNumericId);
24// Result of find (name === 'Bob'): { id: 2, name: 'Bob' }
25// Result of findIndex (id === 3): 2
26// Result of some (id === 2): true
27// Result of every (id is number): true
findmemulangkan elemen pertama yang memenuhi syarat.findIndexmemulangkan indeks elemen yang memenuhi syarat.somememulangkantruejika sekurang-kurangnya ada satu elemen yang memenuhi syarat.everymemulangkantruejika semua elemen memenuhi syarat.
Semua kaedah ini sangat berguna dalam pemprosesan array, jadi menggunakannya dengan tepat pada situasi sesuai akan menjadikan kod anda padat dan jelas.
Fungsi Susunan dan Perbandingan
Array disusun menggunakan sort, tetapi secara lalai ia membandingkan elemen sebagai string, yang boleh mengakibatkan keputusan yang tidak dijangka semasa menyusun nombor.
1const nums = [10, 2, 33, 4];
2console.log("Original nums:", nums);
3
4// Default sort: compares elements as strings (not suitable for numbers)
5nums.sort();
6console.log("\nAfter default sort (string comparison):", nums);
7
8// Numeric ascending sort using a compare function
9nums.sort((a, b) => a - b);
10console.log("After numeric sort (a - b):", nums);
11
12// Sort objects by a property
13const people = [{ age: 30 }, { age: 20 }, { age: 25 }];
14console.log("\nOriginal people:", people);
15
16people.sort((a, b) => a.age - b.age);
17console.log("After sorting people by age:", people);
18
19// After default sort (string comparison): [ 10, 2, 33, 4 ]
20// After numeric sort (a - b): [ 2, 4, 10, 33 ]
21// Original people: [ { age: 30 }, { age: 20 }, { age: 25 } ]
22// After sorting people by age: [ { age: 20 }, { age: 25 }, { age: 30 } ]
- Apabila menyusun nombor atau objek, sentiasa tentukan fungsi perbandingan untuk menyusun mengikut aturan yang dikehendaki.
- Dalam fungsi perbandingan, nilai negatif meletakkan
asebelumb, nilai positif meletakkanbsebeluma, dan nilai 0 mengekalkan susunan mereka.
Menyalin Array dan Ketidakbolehubahan
Apabila menyalin array, penting untuk memahami perbezaan antara 'salinan rujukan' dan 'salinan cetek.'. Secara khusus, sedar bahawa jika terdapat objek dalam array, salinan cetek akan menyebabkan objek dalaman dikongsi.
Salinan rujukan
Apabila anda menetapkan satu array kepada pemboleh ubah lain, array itu sendiri tidak diduplikasi; sebaliknya, 'rujukan' yang menunjuk kepada array yang sama disalin.
1const a = [1, 2, 3];
2console.log("Original a:", a);
3
4// Reference copy; modifying b also affects a
5const b = a;
6console.log("\nReference copy b = a:", b);
7// Reference copy b = a: [ 1, 2, 3 ]
8
9b[0] = 100;
10console.log("After modifying b[0] = 100:");
11console.log("a:", a); // a: [ 100, 2, 3 ] (affected)
12console.log("b:", b); // b: [ 100, 2, 3 ]
- Dengan salinan rujukan, jika anda mengubah kandungan array menggunakan pemboleh ubah salinan, perubahan itu juga akan terpapar pada pemboleh ubah asal yang merujuk kepada array yang sama.
Salinan cetek
Menggunakan slice() atau sintaks sebaran menghasilkan 'salinan cetek' kerana hanya nilai-nilai yang diduplikasi; array asal dan salinan dianggap sebagai entiti berasingan.
1const a = [1, 2, 3];
2console.log("Original a:", a);
3
4// Shallow copy (new array)
5const b = a.slice();
6console.log("\nShallow copy using slice():", b);
7// Shallow copy using slice(): [ 100, 2, 3 ]
8
9const c = [...a];
10console.log("Shallow copy using spread [...a]:", c);
11// Shallow copy using spread [...a]: [ 100, 2, 3 ]
12
13// Modifying c or d does NOT affect a
14b[1] = 200;
15c[2] = 300;
16console.log("\nAfter modifying b[1] = 200 and c[2] = 300:");
17console.log("a:", a); // [ 100, 2, 3 ]
18console.log("b:", b); // [ 100, 200, 3 ]
19console.log("c:", c); // [ 100, 2, 300 ]
- Kod ini menunjukkan bahawa salinan cetek array yang dicipta dengan
slice()atau sintaks sebaran tidak mempengaruhi array asal.
Salinan cetek dan kebolehubahan
Walaupun anda menduplikasi array menggunakan 'salinan cetek,' perkongsian tidak disengajakan mungkin berlaku jika array mengandungi objek di dalamnya.
1// Shallow copy doesn't clone inner objects
2const nested = [{ x: 1 }, { x: 2 }];
3console.log("\nOriginal nested:", nested);
4// Original nested: [ { x: 1 }, { x: 2 } ]
5
6const shallow = nested.slice();
7console.log("Shallow copy of nested:", shallow);
8// Shallow copy of nested: [ { x: 1 }, { x: 2 } ]
9
10// Changing inner object affects both arrays
11shallow[0].x = 99;
12console.log("\nAfter shallow[0].x = 99:");
13console.log("nested:", nested);
14console.log("shallow:", shallow);
15// nested: [ { x: 99 }, { x: 2 } ]
16// shallow: [ { x: 99 }, { x: 2 } ]
- Kod ini menunjukkan bahawa dengan salinan cetek, objek dalaman dikongsi, jadi mengubah objek dalaman itu akan mempengaruhi kedua-dua array asal dan salinan.
- Jika anda memerlukan data yang bebas, anda perlu membuat 'salinan dalam' seperti menggunakan
structuredClone()atau penukaran JSON.
Kaedah utiliti yang berguna
Berikut adalah kaedah utiliti yang kerap digunakan semasa bekerja dengan array. Dengan menggunakannya secara sesuai mengikut tujuan anda, anda boleh menulis kod yang ringkas dan mudah dibaca.
includes
Kaedah includes memeriksa sama ada nilai tertentu terdapat dalam array.
1// includes: check if array contains a value
2const letters = ['a', 'b', 'c'];
3const hasB = letters.includes('b');
4console.log("letters:", letters); // [ 'a', 'b', 'c' ]
5console.log("letters.includes('b'):", hasB); // true
- Dalam kod ini, kaedah
includesdigunakan untuk menentukan secara ringkas sama ada nilai tertentu wujud dalam array.
concat
Kaedah concat mengembalikan array baharu yang menambah array atau nilai tertentu ke hujung, sambil mengekalkan array asal tanpa perubahan.
1// concat: merge arrays without mutation
2const a1 = [1, 2];
3const a2 = [3, 4];
4const combined = a1.concat(a2);
5console.log("a1.concat(a2):", combined); // [ 1, 2, 3, 4 ]
6console.log("a1(unchanged):", a1); // [ 1, 2 ]
- Kod ini menunjukkan bahawa
concattidak merosakkan, membolehkan anda menjana array baharu sambil mengekalkan array asal.
flat
Dengan menggunakan kaedah flat, anda boleh memaplas array bersarang.
1// flat and flatMap: flatten arrays or map + flatten in one step
2const nested = [1, [2, [3]]];
3console.log("nested:", nested); // nested: [ 1, [ 2, [ 3 ] ] ]
4console.log("nested.flat():", nested.flat()); // default depth = 1
5// nested.flat(): [ 1, 2, [ 3 ] ]
- Kod ini menunjukkan hasil dari memaplas array pada satu peringkat.
- Oleh kerana
flatmembenarkan anda menentukan kedalaman, anda boleh menyelesaikan sarang dengan fleksibel mengikut keperluan.
flatMap
Kaedah flatMap mengaplikasikan transformasi pada setiap elemen dan kemudian secara automatik memaplas hasilnya menjadi array satu dimensi.
1// flat and flatMap: flatten arrays or map + flatten in one step
2const words = ['hello world', 'hi'];
3console.log("words:", words); // [ 'hello world', 'hi' ]
4
5const splitWords = words.flatMap(w => w.split(' '));
6console.log("words.flatMap(w => w.split(' ')):", splitWords);
7// words.flatMap(w => w.split(' ')): [ 'hello', 'world', 'hi' ]
- Kod ini menunjukkan contoh di mana setiap rentetan dalam array dipecahkan mengikut ruang, dan hasilnya digabungkan serta dipaplas menjadi satu array.
join
Kaedah join menghasilkan satu rentetan dengan menggabungkan elemen-elemen array menggunakan pemisah yang ditetapkan.
1// join: combine elements into a string with a separator
2const csv = ['a', 'b', 'c'].join(',');
3console.log("['a', 'b', 'c'].join(','):", csv); // a,b,c
- Dalam kod ini, kaedah
joindigunakan untuk menukarkan array kepada rentetan yang dipisahkan dengan koma.
Perangkap Biasa
Operasi array mungkin kelihatan mudah pada pandangan pertama, tetapi terdapat beberapa perkara yang boleh menyebabkan tingkah laku yang tidak dijangka. Banyak perangkap mudah terlepas pandang semasa operasi array harian, jadi mengingati perkara-perkara berikut akan meningkatkan kebolehpercayaan kod anda.
sort()padaArraymenyusun mengikut perbandingan string secara lalai. Untuk menyusun nombor dengan betul, anda mesti sentiasa menyediakan fungsi perbandingan.- Menyalin array (melalui
sliceatau sintaks spread dll.) menghasilkan salinan cetek. Jika array anda mengandungi objek, berhati-hatilah kerana data asal mungkin akan berubah tanpa sengaja. spliceialah kaedah yang merosakkan dan terus mengubah array, manakalasliceialah kaedah tidak merosakkan yang tidak mengubah array asal. Adalah penting untuk menggunakan kaedah-kaedah ini dengan sewajarnya mengikut keperluan anda.forEachtidak sesuai untuk gelung dengan pemprosesan asinkron menggunakanawait. Jika anda ingin melaksanakan pemprosesan asinkron secara berurutan dengan yakin, disarankan untuk menggunakanfor...of.
Contoh Praktikal
Di bawah ialah contoh yang menggabungkan kaedah array untuk 'mengira jumlah umur daripada data pengguna, mengekstrak mereka yang berumur 30 tahun ke atas, dan membina senarai nama.'.
1const users = [
2 { name: 'Alice', age: 28 },
3 { name: 'Bob', age: 34 },
4 { name: 'Carol', age: 41 },
5 { name: 'Dave', age: 19 }
6];
7
8console.log("Users:", users);
9
10// sum ages
11const totalAge = users.reduce((acc, u) => acc + u.age, 0);
12console.log("\nTotal age of all users:", totalAge);
13// Total age of all users: 122
14
15// filter and map names of users 30 and older
16const namesOver30 = users
17 .filter(u => u.age >= 30)
18 .map(u => u.name);
19
20console.log("Users aged 30 or older (names):", namesOver30);
21// Users aged 30 or older (names): [ 'Bob', 'Carol' ]
- Dengan menggabungkan
reduce,filter, danmap, anda boleh menulis pengagregatan, pengekstrakan syarat, dan penukaran data dengan lebih mudah. - Saluran pemprosesan data seperti ini sangat mudah dibaca, dan sebagai gaya yang kurang kesan sampingan, ia sering digunakan dalam aplikasi sebenar.
Ringkasan
Dengan array JavaScript, walaupun operasi asas adalah sangat berguna, dan melalui penggunaan fungsi aras tinggi, kod anda menjadi lebih padat serta berfungsi. Terdapat banyak perkara yang perlu difahami, tetapi setelah anda menguasai cara menggunakan setiap kaedah dengan tepat, pemprosesan data akan menjadi lebih lancar.
Anda boleh mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Sila lihat juga saluran YouTube kami.