Operatory i wyrażenia (operacje na zmiennych)

Operatory to specjalne symbole służące do wykonywania operacji na danych, takich jak liczby czy teksty zapisane w zmiennych. Wyrażenie to kombinacja wartości, zmiennych i operatorów, która jest obliczana (ewaluowana) do jednej wartości. Innymi słowy, wyrażenie z użyciem operatorów pozwala nam uzyskać nową wartość na podstawie istniejących danych. Na przykład, w wyrażeniu c = a + b; używamy operatora + do dodania wartości zmiennych a i b, a wynik przypisujemy za pomocą operatora = do zmiennej c. W wyniku wykonania takiej instrukcji zmienna c będzie zawierać sumę wartości a i b. Poniżej przedstawiono ten przykład w kodzie:

 let a = 5; let b = 3;
 let c = a + b;  // dodajemy wartości a i b, wynik (8) przypisujemy do c
 console.log(c); // wypisze 8, ponieważ 5 + 3 = 8

W powyższym kodzie + i = to operatory, a cała instrukcja c = a + b jest wyrażeniem przypisania, które najpierw oblicza sumę, a następnie przypisuje wynik do zmiennej c. Zmienna c przyjmie nową wartość w wyniku tej operacji.

JavaScript udostępnia wiele operatorów, które możemy podzielić na różne kategorie w zależności od ich przeznaczenia. Poniżej omówimy najważniejsze rodzaje operatorów oraz to, jak działają one na zmiennych i wartościach.

  • Operatory arytmetyczne (matematyczne): służą do wykonywania podstawowych operacji matematycznych na liczbach.
    • + (dodawanie) – sumuje dwie wartości. Może także służyć do łączenia tekstów (konkatenacji stringów).- (odejmowanie) – odejmuje drugą wartość od pierwszej.* (mnożenie) – mnoży dwie wartości./ (dzielenie) – dzieli pierwszą wartość przez drugą.% (modulo) – zwraca resztę z dzielenia pierwszej wartości przez drugą (np. 7 % 3 daje 1, bo 7 dzielone przez 3 ma resztę 1).** (potęgowanie) – podnosi pierwszą wartość do potęgi drugiej (np. 2 ** 3 to 2 do potęgi 3, czyli 8).
      Przykłady użycia operatorów arytmetycznych:
 let x = 10; 
 let y = 4; 
 console.log(x + y); // 14 (dodawanie 10 + 4) 
 console.log(x - y); // 6 (odejmowanie 10 - 4) 
 console.log(x * y); // 40 (mnożenie 10 * 4) 
 console.log(x / y); // 2.5 (dzielenie 10 / 4) 
 console.log(x % y); // 2 (reszta z dzielenia 10 / 4, ponieważ 4*2 = 8, reszta 2) 
 console.log(2 ** 3); // 8 (potęgowanie, 2 do potęgi 3)

W powyższych przykładach wykorzystano zmienne x i y do demonstracji podstawowych działań arytmetycznych. Warto zauważyć, że operatory +, -, *, / działają podobnie jak w matematyce. Operator % (modulo) często bywa użyteczny do sprawdzania podzielności liczby (gdy a % b == 0, to a dzieli się przez b bez reszty). Z kolei operator ** jest wygodnym sposobem zapisu potęgowania (zamiast funkcji Math.pow()).

  • Operatory przypisania: służą do przypisywania wartości zmiennym. Najprostszy operator przypisania to znak równości = używany już w powyższych przykładach. Lewa strona operatora = wskazuje zmienną, której chcemy nadać wartość, a prawa strona to wyrażenie, które zostanie obliczone, a jego wynik przypisany. Oprócz podstawowego =, JavaScript oferuje skrócone operatory przypisania, które łączą operację arytmetyczną z przypisaniem:
    • x = value – przypisuje zmiennej x wartość value.x += value – dodaje value do aktualnej wartości x i zapisuje wynik ponownie w x (skrót od x = x + value).x -= value – odejmuje value od aktualnej wartości x (skrót od x = x - value).x *= value – mnoży aktualną wartość x przez value (skrót od x = x * value).x /= value – dzieli aktualną wartość x przez value (skrót od x = x / value).x %= value – zastępuje x resztą z dzielenia x przez value (skrót od x = x % value).
      Poniższy fragment kodu ilustruje działanie operatorów przypisania:
 let liczba = 7;
 console.log(liczba); // 7 (początkowa wartość) liczba = 10; 
 console.log(liczba); // 10 (po przypisaniu nowej wartości za pomocą =) liczba += 5;    
 console.log(liczba); // 15 (dodano 5, więc 10 + 5) liczba *= 2; 
 console.log(liczba); // 30 (pomnożono przez 2, więc 15 * 2) liczba -= 10; 
 console.log(liczba); // 20 (odjęto 10, więc 30 - 10)

W kodzie powyżej zmienna liczba najpierw otrzymuje wartość 7. Następnie kolejno przypisujemy jej nowe wartości, pokazując przy tym użycie skróconych operatorów przypisania. Po wykonaniu liczba += 5 zmienna zwiększa swoją wartość o 5 (z 10 na 15). Operator *= podwaja wartość zmiennej (15 staje się 30), a operator -= zmniejsza wartość o 10 (30 staje się 20).

  • Operatory inkrementacji i dekrementacji: są to specjalne operatory arytmetyczne służące do zwiększania lub zmniejszania wartości zmiennej o 1. Operator inkrementacji ++ zwiększa wartość zmiennej o jeden, a dekrementacji -- zmniejsza o jeden. Istnieją dwa warianty tych operatorów:
    • Post-inkrementacja (x++) – zwraca bieżącą wartość x, a następnie zwiększa x o 1.Pre-inkrementacja (++x) – najpierw zwiększa wartość x o 1, a następnie zwraca nową wartość. (Analogicznie dla dekrementacji: x-- zwraca najpierw starą wartość i potem zmniejsza, a --x zmniejsza najpierw i zwraca zmniejszoną).
      Różnicę między tymi wariantami najlepiej zrozumieć na przykładzie:
 let i = 5; 
 console.log(i++); // wypisuje 5, *najpierw* zwraca starą wartość, potem i=6 
 console.log(i); // wypisuje 6, zmienna i została zwiększona w poprzedniej operacji   
 console.log(++i); // wypisuje 7, bo najpierw inkrementuje (6->7), potem zwraca 7  
 console.log(i); // wypisuje 7, i pozostało zwiększone

W powyższym kodzie początkowo i wynosi 5. Gdy wykonujemy console.log(i++), zostanie wyświetlone 5 (wartość przed inkrementacją), ale wewnętrznie i zwiększy się do 6. Następne wywołanie console.log(i) potwierdza, że i jest już równe 6. Natomiast console.log(++i) od razu zwiększa i do 7 i zwraca tę nową wartość, więc wypisuje 7. Ostatecznie i ma wartość 7. Warto używać pre- lub post-inkrementacji świadomie, zwłaszcza wewnątrz bardziej złożonych wyrażeń, aby uniknąć pomyłek.

  • Operatory porównania (relacyjne): umożliwiają porównywanie dwóch wartości. Wynikiem wyrażenia porównania jest zawsze wartość logiczna true (prawda) lub false (fałsz). Operatory te są podstawą do podejmowania decyzji w programie (np. w instrukcjach warunkowych). Do operatorów porównania należą:
    • == – porównanie luźne (równość wartości): zwraca true, jeśli wartości po obu stronach są sobie równe po dokonaniu konwersji typu. Np. 5 == "5" zwróci true, bo string „5” zostanie skonwertowany na liczbę 5, która równa się 5.=== – porównanie ścisłe (identyczność): zwraca true tylko, jeśli operandy są równe i mają ten sam typ. Np. 5 === "5" da false, ponieważ mimo że wartości numeryczne są równe, to porównywane są różne typy (number vs string). Z kolei 5 === 5 da true (ta sama wartość i typ).!= – operator „różne” (negacja luźnego porównania): zwraca true, jeśli dwie wartości nie są sobie równe (po ewentualnej konwersji typu). Np. 5 != "5" da false (bo po konwersji „5” na 5 wartości są równe, więc nie są różne).!== – operator „ściśle różne”: zwraca true, jeśli wartości albo ich typy są różne (brak identyczności). Np. 5 !== "5" da true (bo typy są różne, więc wartości nie są identyczne), a 5 !== 5 da false (bo zarówno wartość, jak i typ są takie same).< – mniejszy niż: x < y jest true, jeśli x jest mniejsze od y.<= – mniejszy lub równy: x <= y jest true, jeśli x jest mniejsze lub równe y.> – większy niż: x > y jest true, jeśli x jest większe od y.>= – większy lub równy: x >= y jest true, jeśli x jest większe lub równe y.
      Przykłady zastosowania operatorów porównania:
 console.log(10 > 5); // true (10 jest większe od 5) 
 console.log(10 < 5); // false (10 nie jest mniejsze od 5) 
 console.log(5 == "5"); // true (równe po konwersji typu string "5" -> number 5) 
 console.log(5 === "5"); // false (różny typ, porównanie ścisłe nie przejdzie) 
 console.log(7 != "7"); // false (7 i "7" po konwersji uznane za równe, więc "nie równe" jest fałszem) 
 console.log(7 !== "7"); // true (7 jako liczba i "7" jako tekst nie są identyczne)   
 console.log(8 >= 8); // true (8 jest równe 8, więc spełnia warunek ">= 8") 
 console.log(9 <= 8); // false (9 nie jest mniejsze ani równe 8)

Gdy korzystamy z operatorów porównania, warto pamiętać o różnicy między == a ===. W JavaScript operator podwójnego równości == dokonuje automatycznej konwersji typów, co czasem może prowadzić do nieintuicyjnych rezultatów dla mniej oczywistych porównań (np. 0 == false jest true, ponieważ false zostanie skonwertowane na 0). Dlatego w nowoczesnym JavaScript zaleca się stosowanie raczej operatorów ścisłej równości === i ścisłej różności !== – są one bardziej przewidywalne, bo nie wykonują ukrytego rzutowania typów.

  • Operatory logiczne: pozwalają łączyć wyrażenia logiczne (porównania) i operować na wartościach boolean (true/false). Najważniejsze z nich to:
    • && (logiczne i, ang. AND) – zwraca true wtedy i tylko wtedy, gdy oba warunki/operandy są prawdziwe. Jeśli chociaż jeden jest fałszywy, wynik będzie false.|| (logicjne lub, ang. OR) – zwraca true, gdy przynajmniej jeden z warunków jest spełniony (prawdziwy). Wynik jest false tylko, gdy oba warunki są fałszywe.! (logicza negacja, ang. NOT) – zwraca wartość przeciwną do operandu logicznego: z true robi false, z false robi true. Używany do odwracania warunków.
    Przy pomocy operatorów logicznych możemy budować bardziej złożone warunki logiczne, łącząc kilka porównań. Na przykład, warunek „X jest większe od 0 i mniejsze od 10″ możemy zapisać jako (X > 0 && X < 10). Z kolei warunek „liczba jest parzysta lub większa od 100″ zapiszemy jako (liczba % 2 == 0 || liczba > 100). Przykłady działania operatorów logicznych:
 let x = 5; 
 let y = 12; 
 console.log(x > 0 && y > 0); // true (oba warunki są prawdziwe: x>0 i y>0) 
 console.log(x > 10 && y > 0); // false (pierwszy warunek x>10 jest fałszywy) 
 console.log(x % 2 == 1 || y % 2 == 1); // true (x jest nieparzyste LUB y jest nieparzyste; tu x%2==1 jest true) 
 console.log(!(x > 0)); // false (negacja true daje false; x > 0 było true, więc !true -> false)

W powyższym kodzie pokazano kilka kombinacji: użycie && sprawia, że cały warunek jest spełniony tylko, jeśli wszystkie części składowe są spełnione (przykład z x > 0 && y > 0). Operator || zwraca true, jeśli spełniony jest przynajmniej jeden z warunków (sprawdziliśmy, czy któraś z liczb x lub y jest nieparzysta). Operator ! odwraca wartość logiczną warunku (jeżeli x > 0 jest prawdą, to !(x > 0) będzie fałszem).

Warto wspomnieć, że operatory logiczne && i || podlegają mechanizmowi leniwej ewaluacji (ang. short-circuiting). Oznacza to, że w wyrażeniu logicznym JavaScript może pominąć sprawdzanie drugiej części, jeśli wynik można jednoznacznie określić na podstawie pierwszej. Na przykład, w wyrażeniu (warunek1 && warunek2) jeśli warunek1 okaże się fałszywy, to całość i tak będzie fałszywa – interpreter nie sprawdza już warunek2. W (warunek1 || warunek2) analogicznie, gdy pierwszy warunek jest prawdziwy, całość jest prawdziwa bez sprawdzania drugiego. Ta właściwość bywa wykorzystywana w praktyce do pisania zwięzłego kodu, ale na poziomie początkującym wystarczy rozumieć, że istnieje i dlaczego może czasem np. nie dojść do wykonania jakiejś funkcji umieszczonej jako drugi warunek.

Na koniec tej części należy zauważyć, że wyrażenia w JavaScript mogą zawierać wiele operatorów na raz. W takich sytuacjach obowiązuje priorytet operatorów oraz kolejność obliczania. Dla przykładu, w wyrażeniu 1 + 2 * 3 najpierw wykonywane jest mnożenie (2 * 3 = 6), a dopiero potem dodawanie 1 + 6 = 7, ponieważ operator * ma wyższy priorytet niż +. Można i warto używać nawiasów () w celu wymuszenia własnej kolejności lub po prostu dla czytelności. Na przykład zapis (1 + 2) * 3 sprawi, że dodawanie wykona się przed mnożeniem (dając wynik 9). Jeśli nie jesteśmy pewni, który operator wykona się jako pierwszy, najlepiej dodać nawiasy lub rozbić wyrażenie na mniejsze części – poprawi to czytelność kodu i zmniejszy ryzyko błędów.

Podsumowując, operatory i wyrażenia pozwalają nam manipulować danymi i wykonywać obliczenia. Dzięki nim możemy na przykład obliczać formuły matematyczne, porównywać wartości czy łączyć teksty. Rezultaty operacji często wykorzystujemy w kolejnych instrukcjach programu – szczególnie ważne jest użycie wyników porównań i operacji logicznych w instrukcjach warunkowych, które omówimy w następnej części.