Javascript – Set()

article-thumbnail

W standardzie ES6 wprowadzono do języka Javascript nowe typy danych. Jednym z nich jest Set. Zasadniczo pełni on podobną funkcję jak tablica, jednak występują pewne różnice. Najistotniejszą jest jest brak powtarzania się elementów wewnątrz. Ponadto set nie posiada indeksów, przez co nie możemy odwołać się bezpośrednio do szukanej komórki.

Deklaracja

Deklaracja set’u odbywa się tak samo jak każdego innego obiektu. Używamy słowa kluczowego new i dodajemy konstruktor klasy Set. Wygląda to tak:

<script>
	const set = new Set();
</script>

Dodawanie wartości

Aby dodać do niego dane używamy metody add(). Przyjmie ona jako argument wartość do dodania do kolekcji. Jako że jest to typ iterowalny (czyli możemy użyć na nim pętli) posiada on metodę forEach(), dzięki której możemy „dobrać się” do zawartości kolekcji.

<script>
	const set = new Set();
	set.add(1);
	set.add(' Tekst ');
	set.add(3);
	set.add(1);
	set.forEach(value => document.write(value))
</script>

Jak widać na powyższym przykładzie dane zostały dodane do kolekcji. Jednak dodana dwukrotnie liczba 1 pojawiła się tylko raz. Potwierdza to, że Set przechowuje tylko wartości unikalne. Co jednak się stanie gdy spróbujemy dodać do niego obiekty?

Aby wynik był wiarygodny musimy zrealizować kilka scenariuszów. Podstawowym jest dodanie dwa razy tego samego obiektu. Następnie dodamy dwa obiekty o różnej strukturze, potem obiekt i jego referencję, a na końcu dwa identyczne obiekty (tak samo zdefiniowane). Pozwoli nam to uzyskać pełen obraz działania kolekcji.

<script>
	const set = new Set();
	
	const obiekt1 = {a: 5}
    set.add(obiekt1);
	set.add(obiekt1);

	document.write('Wynik: </br>');
	set.forEach(value => document.write(JSON.stringify(value)));
</script>

Uzyskaliśmy jeden rezultat. Oznacza to set porównuje obiekty do niego dodawane.

<script>
	const set = new Set();
	
	const obiekt1 = {a: 5}
    const obiekt2 = {a: 4}
    set.add(obiekt1);
	set.add(obiekt2);

	document.write('Wynik: </br>');
	set.forEach(value => document.write(JSON.stringify(value)));
</script>

Uzyskaliśmy dwa rezultaty. Nie ma się oczywiście czemu dziwić – dodaliśmy dwa różne obiekty więc oba została zapamiętane.

<script>
	const set = new Set();
	
	const obiekt1 = {a: 5}
    const obiekt2 = obiekt1

    set.add(obiekt1);
	set.add(obiekt2);

	document.write('Wynik: </br>');
	set.forEach(value => document.write(JSON.stringify(value)));
</script>
<script>
	const set = new Set();
	
	const obiekt1 = {a: 5}
    const obiekt2 = {...obiekt1}
    set.add(obiekt1);
	set.add(obiekt2);

	document.write('Wynik: </br>');
	set.forEach(value => document.write(JSON.stringify(value)));
</script>

Na podstawie wyników prób 3 i 4 widzimy, że porównywaną wartością nie jest „zawartość ” obiektu a jego referencja – adres w pamięci. Oznacza to, że nie możemy użyć kolekcji do unikania powtórzeń wśród obiektów (z wyjątkiem odwołań). Jednak jest sposób by to obejść. Wystarczy zamienić obiekt na ciąg znaków metodą JSON.stringify().

Usuwanie wartości

Klasa Set dostarcza dwie metody służące do usuwania zawartości. Pierwszą z nich jest clear(), która usuwa wszystkie elementy w kolekcji. Natomiast drugą metodą jest delete(), która usuwa jedynie wskazaną wartość o ile ta istnieje. Oto przykładowa implementacja metody clear():

<script>
	const set = new Set();
	set.add(1);
	set.add(' Tekst ');
	set.add(3);
	set.add(1);
	set.clear();
	set.forEach(value => document.write(value))
</script>

Jeżeli natomiast chcemy usunąć konkretną wartość użyjemy delete().

<script>
	const set = new Set();
	set.add(1);
	set.add(' Tekst ');
	set.add(3);
	set.add(1);
	set.delete(' Tekst ');
	set.forEach(value => document.write(value))
</script>

Metodę delete możemy połączyć z pętlą forEach. Można tego użyć chociażby do oczyszczenia kolekcji z nieużytecznych danych np.:

<script>
	const set = new Set();
	set.add(1);
	set.add('Tekst');
	set.add(3);
	set.add(1);
	set.forEach(value=>{
    	if(typeof value !== 'number') set.delete(value);
    })
	set.forEach(value => document.write(value + ','))
</script>

Jeżeli chcemy usunąć jakąś wartość, musimy ją znać. Dlatego możemy użyć metody has(), która sprawdzi czy w kolekcji znajduje się podana w argumencie wartość.

<script>
	const set = new Set();
	set.add(1);
	set.add(3);
	set.add(1);
	const result1 = set.has(1);
    const result2 = set.has(2);
    document.write(result1 + '</br>');
	document.write(result2);
</script>

Tworzenie w oparciu o już istniejącą tablicę.

Na koniec chciałem wspomnieć o jeszcze jednej możliwości – tworzeniu kolekcji w oparciu o tablicę lub set. Jest to banalne. Wystarczy podać jako argument konstruktora obiekt tablicy lub set.

<script>
	const set = new Set([1,2,3,4,1]);
	set.forEach(value => document.write(value + ','))
</script>