Objek `Set`

Artikel ini menerangkan tentang objek Set.

Kami akan menerangkan objek Set dengan contoh-contoh praktikal.

YouTube Video

Objek Set

Set ialah objek terbina dalam yang digunakan untuk mengurus koleksi nilai unik tanpa pendua. Ia membolehkan anda menulis kod untuk menghapus pendua dan semakan kewujudan dengan lebih mudah berbanding dengan array, serta memudahkan pelaksanaan operasi set seperti gabungan (union) dan persilangan (intersection).

Asas: Mewujudkan dan Menggunakan Set

Pertama sekali, mari lihat cara mewujudkan Set, menambah dan membuang elemen, menyemak kewujudan nilai, dan mendapatkan saiznya.

Di bawah ini adalah corak asas yang mewujudkan Set baru dan menunjukkan penggunaan add, has, delete, dan size.

 1// Create a Set and demonstrate add, has, delete, and size
 2const s = new Set();
 3
 4s.add(1);
 5s.add(2);
 6s.add(2); // duplicate, ignored
 7
 8console.log(s.has(1)); // true
 9console.log(s.has(3)); // false
10
11s.delete(2);
12console.log(s.size); // 1
13
14console.log([...s]); // [1]
  • Seperti yang ditunjukkan dalam kod ini, Set secara automatik membuang nilai primitif yang berulang, dan anda boleh mendapatkan bilangan elemen menggunakan size.

Kaedah iterasi

Set boleh diulang (iterable), jadi anda boleh mengitarinya menggunakan for...of atau forEach. Susunan elemen adalah mengikut turutan kemasukan.

Berikut ialah cara lazim untuk menggunakan for...of dan forEach.

 1// Iterate a Set with for...of and forEach
 2const s = new Set(['a', 'b', 'c']);
 3
 4for (const v of s) {
 5  console.log('for...of:', v);
 6}
 7
 8s.forEach((value, sameValue, setRef) => {
 9  // Note: second arg is same as first for Set API to match Map signature
10  console.log('forEach:', value);
11});
  • Tandatangan callback untuk forEach adalah value, value, set (untuk keserasian dengan Map), tetapi dalam amalan, anda biasanya hanya memerlukan argumen value yang pertama sahaja.

Penukaran antara Array dan Set (berguna untuk membuang pendua)

Di sini kami tunjukkan teknik mudah untuk membuang pendua daripada array, dan cara menukar Set kembali kepada array.

Di bawah ialah contoh membuang pendua daripada array dengan menukar ia kepada Set.

1// Deduplicate an array using Set
2const arr = [1, 2, 2, 3, 3, 3];
3const deduped = [...new Set(arr)];
4console.log(deduped); // [1, 2, 3]
5
6// Convert a Set to an array using Array.from
7const s = new Set([4, 5, 6]);
8const arrFromSet = Array.from(s);
9console.log(arrFromSet); // [4, 5, 6]
  • Corak ini ringkas dan pantas, jadi ia sering digunakan untuk membuang pendua dalam array. Ia sangat berkesan untuk nilai-nilai primitif.

Objek dan Pengendalian Rujukan

Objek dalam Set dibandingkan berdasarkan rujukan, jadi objek berbeza walaupun dengan kandungan yang sama akan dianggap sebagai elemen yang berasingan.

Kod berikut menunjukkan apa yang berlaku apabila anda menambah objek ke dalam Set.

 1// Objects are compared by reference in a Set
 2const obj1 = { x: 1 };
 3const obj2 = { x: 1 };
 4
 5const s = new Set();
 6s.add(obj1);
 7s.add(obj2);
 8
 9console.log(s.size); // 2 (different references)
10console.log(s.has(obj1)); // true
11console.log(s.has({ x: 1 })); // false (different object)
  • Pengesanan pendua untuk objek adalah berdasarkan identiti rujukan, jadi jika anda ingin menghapuskan pendua berdasarkan kandungan objek sahaja, anda perlu mensiri atau memprosesnya dengan cara lain.

Nilai Khas: Pengendalian NaN dan -0/+0

Set menggunakan peraturan perbandingan Same-value-zero untuk menentukan kesamaan nilai. Kaedah perbandingan ini mempunyai ciri-ciri berikut berkaitan nombor:.

  • NaN dianggap sama dengan NaN.
  • +0 (positif) dan -0 (negatif) tidak dibezakan dan dianggap sebagai nilai yang sama.

Oleh itu, apabila anda menambah nilai-nilai ini ke dalam Set, kelakuan berikut berlaku:.

 1// NaN and zero behavior in Set
 2const s = new Set();
 3
 4s.add(NaN);
 5s.add(NaN);
 6console.log(s.size); // 1 (NaN considered the same)
 7
 8s.add(+0);
 9s.add(-0);
10console.log(s.size); // still 2 (NaN + 0)
11console.log([...s]); // [NaN, 0] (order may vary but only one zero)
  • Dalam perbandingan biasa (NaN === NaN), ia menghasilkan false, tetapi di dalam Set, semua nilai NaN dianggap sebagai 'nilai yang sama'.
  • +0 dan -0 boleh dibezakan secara matematik, tetapi dalam Set, kedua-duanya dianggap hanya sebagai 0.
  • Akibatnya, hanya satu NaN dan satu 0 yang kekal dalam Set.
  • Peraturan perbandingan Set adalah hampir sama dengan Object.is, tetapi tidak seratus peratus sama. Object.is(+0, -0) menghasilkan false, tetapi dalam Set, kedua-duanya dianggap sama. Sila ambil perhatian tentang perbezaan ini.

Utiliti Lazim: Operasi Set (Gabungan, Persilangan, Perbezaan)

Operasi set boleh ditulis dengan lebih jelas menggunakan Set. Berikut adalah contoh pelaksanaan yang lazim.

Berikut ialah contoh fungsi untuk union (gabungan), intersection (persilangan), dan difference (perbezaan).

 1// Set operations: union, intersection, difference
 2function union(a, b) {
 3  return new Set([...a, ...b]);
 4}
 5
 6function intersection(a, b) {
 7  return new Set([...a].filter(x => b.has(x)));
 8}
 9
10function difference(a, b) {
11  return new Set([...a].filter(x => !b.has(x)));
12}
13
14// Demo
15const A = new Set([1, 2, 3]);
16const B = new Set([3, 4, 5]);
17
18console.log('union', [...union(A, B)]); // [1,2,3,4,5]
19console.log('intersection', [...intersection(A, B)]); // [3]
20console.log('difference A\\B', [...difference(A, B)]); // [1,2]
  • Operasi set boleh ditulis dengan mudah dengan menggunakan penapis (filter) bersama kombinasi Set dan array. Apabila berurusan dengan set data yang besar, prestasi O(1) bagi has menjadikan operasi lebih pantas.

Contoh Praktikal: Mencari Perbezaan Array (Mengesan Item Ditambah/Dibuang)

Contoh berikut menunjukkan cara menggunakan Set untuk mencari perbezaan antara dua array (senarai lama dan senarai baharu). Ini membolehkan anda mengenal pasti elemen yang ditambah dan yang dibuang.

 1// Find added and removed items between two arrays
 2function diffArrays(oldArr, newArr) {
 3  const oldSet = new Set(oldArr);
 4  const newSet = new Set(newArr);
 5
 6  const added = [...newSet].filter(x => !oldSet.has(x));
 7  const removed = [...oldSet].filter(x => !newSet.has(x));
 8
 9  return { added, removed };
10}
11
12const oldList = [1, 2, 3];
13const newList = [2, 3, 4, 5];
14
15console.log(diffArrays(oldList, newList));
16// { added: [4,5], removed: [1] }
  • Kaedah ini sangat mudah untuk mengesan perbezaan dalam senarai ID, senarai tag, dan situasi yang serupa. Ia paling mudah digunakan untuk nilai-nilai primitif.

Perbezaan Antara WeakSet dan Set (Pengurusan Memori)

WeakSet adalah serupa dengan Set, tetapi ia menggunakan rujukan lemah (weak references), membolehkan itemnya dipadam secara automatik (garbage collected). Berikut menunjukkan penggunaan asas bagi WeakSet.

1// WeakSet basics (objects only, not iterable)
2const ws = new WeakSet();
3let obj = { id: 1 };
4ws.add(obj);
5
6console.log(ws.has(obj)); // true
7
8obj = null; // Now the object is eligible for GC; WeakSet won't prevent collection

WeakSet hanya boleh menyimpan objek dan tidak boleh diiterasi. Di bawah ialah contoh-contoh kekangan WeakSet—ia hanya boleh menyimpan objek, dan tidak boleh diiterasi.

 1// WeakSet basics (objects only, not iterable)
 2const ws = new WeakSet();
 3
 4// --- Only objects can be added ---
 5try {
 6	ws.add(1); // number
 7} catch (e) {
 8	console.log("Error: WeakSet can only store objects. Adding a number is not allowed.");
 9}
10
11try {
12	ws.add("text"); // string
13} catch (e) {
14	console.log("Error: WeakSet can only store objects. Adding a string is not allowed.");
15}
16
17// --- WeakSet is not iterable ---
18try {
19	for (const value of ws) {
20		console.log(value);
21	}
22} catch (e) {
23	console.log("Error: WeakSet is not iterable. You cannot use for...of to loop over its elements.");
24}
25
26// --- Cannot convert to array ---
27try {
28	console.log([...ws]);
29} catch (e) {
30	console.log("Error: WeakSet cannot be converted to an array because it does not support iteration.");
31}
32
33// The object becomes eligible for garbage collection
34let obj = { id: 1 };
35ws.add(obj);
36obj = null;
  • WeakSet berguna untuk menjejak kehadiran objek secara sementara, tetapi anda tidak boleh menyenaraikan elemennya atau mendapatkan saiznya.

Prestasi dan Bilakah Sesuai Digunakan

Apabila menentukan sama ada hendak menggunakan Set, adalah penting untuk memahami ciri-ciri prestasinya dan sifat data anda.

  • has, add, dan delete biasanya beroperasi dengan prestasi hampir O(1) secara purata. Oleh itu, dalam situasi di mana anda kerap semak kewujudan nilai atau membuang pendua, Set selalunya lebih berfaedah berbanding array.
  • Berhati-hati jika anda ingin membuang pendua objek berdasarkan kandungan (nilai) mereka. Oleh kerana Set membandingkan berdasarkan rujukan, cara praktikal adalah dengan menggunakan ID atau kunci lain, atau menjadikan objek sebagai nilai primitif sebelum menggunakan Set jika perbandingan berdasarkan nilai diperlukan.
  • Set sangat berguna untuk meningkatkan kebolehbacaan kod bagi koleksi yang kecil hingga sederhana. Sebaliknya, jika anda mengendalikan bilangan elemen yang sangat banyak atau kerap menukar antara array dan Set, disarankan supaya benar-benar melakukan penanda aras dan ujian.

Kesilapan Lazim

Set sangat mudah digunakan, tetapi jika anda tidak menyedari spesifikasinya, anda mungkin keliru dengan tingkah laku yang tidak dijangka. Berikut ialah beberapa perkara lazim yang perlu diberi perhatian:.

  • Objek dibandingkan berdasarkan rujukan, jadi walaupun kandungan mereka sama, objek yang berbeza tidak dianggap sebagai pendua.
  • Set mengekalkan susunan kemasukan, tetapi anda tidak boleh mengakses elemen menggunakan indeks seperti array. Jika anda mahu mengakses berdasarkan indeks, tukarkan Set kepada array dahulu.
  • WeakSet tidak boleh disenaraikan, dan hanya boleh menyimpan objek. Perhatikan bahawa penggunaannya adalah terhad.
  • NaN dianggap nilai yang sama, dan +0 serta -0 tidak dibezakan. Ini disebabkan oleh peraturan perbandingan Same-value-zero.

Ringkasan

Set ialah struktur data yang mudah digunakan untuk mengendalikan koleksi nilai unik secara intuitif. Anda boleh menggunakannya untuk membuang pendua daripada array, melakukan semakan kewujudan dengan pantas, atau melaksanakan operasi set seperti gabungan dan persilangan dengan kod yang ringkas dan mudah dibaca.

Sebaliknya, kerana objek dibandingkan berdasarkan rujukan, langkah tambahan diperlukan jika anda ingin menentukan persamaan berdasarkan kandungannya.

Dengan memahami ciri-ciri ini dan menggunakannya dengan betul, Set menjadi pilihan yang berkuasa untuk meningkatkan kebolehbacaan dan penyenggaraan kod.

Anda boleh mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Sila lihat juga saluran YouTube kami.

YouTube Video