Prioritet operatora u JavaScriptu
Ako želimo da na ispravan način kreiramo izraze u JavaScriptu (kao i u bilo kom drugom programskom jeziku), moramo se upoznati sa redosledom izvršavanja operacija, odnosno sa "snagom" operatora. Redosled operacija će biti predstavljen u sledećoj tabeli, od najjačih, ka najslabijim.
Prioritet | Grupa | Operatori | Asocijativnost | Dostupnost |
---|---|---|---|---|
0 | Operator grupisanja | () | - | |
1 | Pristup elementu objekta | obj.x obj[x] | udesno ▶ | |
Kreiranje instance sa argumenatima | new f(a,b) | - | ||
Poziv funkcije | f() | udesno ▶ | ||
Opciono ulančavanje | obj?.x | udesno ▶ | FF74, C80 | |
2 | Kreiranje instance bez argumenata | new x | ◀ ulevo | |
3 | Sufiksno uvećanje i umanjenje | x++ x-- | - | |
4 | Logička negacija | !x | ◀ ulevo | |
Negacija bitova | ~x | ◀ ulevo | ||
Znak broja | +x -x | ◀ ulevo | ||
Prefiksno uvećanje i umanjenje | ++x --x | ◀ ulevo | ||
Ispitivanje tipa | typeof x | ◀ ulevo | ||
Brisanje elementa objekta | delete obj.x | ◀ ulevo | ||
Poništavanje vrednosti | void x | ◀ ulevo | ||
Razrešavanje promisa | await x | ◀ ulevo | FF52, C55 | |
5 | Stepenovanje | x ** y | ◀ ulevo | FF52, C52 |
6 | Aritmetičke operacije višeg prioriteta | x * y x / y x % y | udesno ▶ | |
7 | Aritmetičke operacije nižeg prioriteta | x + y x - y | udesno ▶ | |
8 | Pomeranje bitova | x << y x >> y x >>> y | udesno ▶ | |
9 | Relacioni operatori | x < y x > y x <= y x >= y | udesno ▶ | |
Svojstvo objekta | x in y | udesno ▶ | ||
Konstruktor objekta | x instanceof y | udesno ▶ | ||
10 | Jednakost i nejednakost | x == y x != y x === y x !== y | udesno ▶ | |
11 | AND nad bitovima | x & y | udesno ▶ | |
12 | XOR nad bitovima | x ^ y | udesno ▶ | |
13 | OR nad bitovima | x | y | udesno ▶ | |
14 | Logička konjunkcija | x && y | udesno ▶ | |
15 | Logička disjunkcija | x || y | udesno ▶ | |
16 | Postojanje vrednosti | x ?? y | ◀ ulevo | FF72, C80 |
17 | Uslovni operator | x ? y : z | ◀ ulevo | |
18 | Operatori dodele | x = y x += y x -= y x *= y x /= y x %= y x <<= y x >>= y x >>>= y x &= y x |= y x ^= y | ◀ ulevo | |
19 | Vrednost generatora | yield x yield* x | ◀ ulevo | |
20 | Operator odvajanja | x, y | udesno ▶ |
*) Dostupnost označava verzije web čitača (FF - Firefox i C - Chrome) za operatore koji su uvedeni nakon poslednjih verzija dostupnih na Windows XP sistemu.
Kada želimo da se određene operacije izvše pre drugih (iako se to ne bi desilo prema redosledu), isto kao u matematici, koristimo zagrade. Zagrade su "najjače" i operacije koje se nalaze unutar njih uvek imaju prednost.
Asocijativnost
Asocijativnost operacija se odnosi na smer evaluacije izraza, ili prostim jezikom, to je smer u kome se razrešavaju operacije u izrazu. To naravno važi samo ako su operatori istog prioriteta, i ako redosled operacija nije promenjen grupisanjem unutar zagrada.
Hajde da prvo pogledamo kako funkcioniše asocijativnost udesno na primeru operacije oduzimanja. Izračunajmo vrednost sledećeg izraza:
10 - 3 - 2 = ?
10 - 3 - 2 = // najpre se od 10 oduzima 3 što daje 7
7 - 2 = // a onda se od 7 oduzima 2
5
Logično, prvo se računa 10 - 3, što daje rezultat 7, a onda se računa razlika tog 7 i 2 i konačni rezultat je 5.
Pravilo asocijativnosti udesno nam govori da se prvo razrešava oduzimanje sa leve strane, pa se onda ide udesno ka poslednjem oduzimanju. Za razliku od npr. sabiranja, ovde redosled jeste bitan. Koji rezultat bismo dobili kada bi za oduzimanje važila asocijativnost ulevo?
10 - 3 - 2 = ?
10 - 3 - 2 = // ako krenemo sa desne strane, 3-2 daje vrednost 1
10 - 1 = // od 10 oduzimamo 1
9 (NEISPRAVNO!)
U takvom slučaju bi se prvo izračunala razlika 3 - 2, a onda bi se od 10 oduzelo tako dobijeno 1, što bi dalo neispravan rezultat 9.
Hajde sada da napravimo sličan primer, ali sa operacijom stepenovanja koja zaista ima asocijativnost ulevo. U ovom primeru računamo rezultat izraza koji bi se matematički zapisao kao 323.
3 ** 2 ** 3 = ?
3 ** 2 ** 3 = // najpre se vrši stepenovanje sa desne strane, 2 na kub je 8
3 ** 8 = // zatim se računa osmi stepen broja 3
6561
Pošto je stepenovanje operacija koja ima asocijativnost ulevo, polazi se od stepenovanja sa desne strane. Dakle prvo se računa stepenovanje 23 što daje 8, a onda se računa stepenovanje 38.
Kada bismo pokušali da računamo od leve strane, dobili bismo neispravan rezultat:
3 ** 2 ** 3 = ?
3 ** 2 ** 3 = // kretanjem s leva, računali bismo prvo 32 što daje 9
9 ** 3 = // a onda bismo 9 podigli na kub
729 (NEISPRAVNO!)
Naravno, prioritet operatora "nadjačava" asocijativnost, što znači da se prvo izračunavaju operacije koje imaju jači prioritet, a tek onda, kada ostanu operacije istog prioriteta, gleda se asocijativnost. Ne brinite - ne možemo doći u dvosmislenu situaciju da se ne zna koja operacija se najpre izvršava, pošto se nikada ne dešava da operatori istog prioriteta imaju različitu asocijativnost.
Primer
Hajde da pogledamo sledeći primer i da pokušamo da rastumačimo šta će biti njegov rezultat i zašto.
var x = 12, y = 8, z = 2;
var rez = y += x + y < 15 ? 1 : 0 - z;
// dakle, prema prioritetu, u ovom izrazu najjače operacije su
// sabiranje i oduzimanje koje se evaluiraju s leva na desno
rez = y += x + y < 15 ? 1 : 0 - z;
rez = y += 20 < 15 ? 1 : 0 - z;
// zatim se vrši operacija poređenja
rez = y += 20 < 15 ? 1 : -2;
// sledeći na redu je ternarni operator izbora
rez = y += false ? 1 : -2;
// na kraju dolaze dva operatora dodele, koji se evaluiraju s desna na levo
rez = y += -2;
rez = 6;
Proverite i sami kako ovo funkcioniše...
- MDN, Operator Precedence
- S. Stefanov, K.C. Sharma (2013): Object-Oriented JavaScript, 2nd.ed, Packt Publishing, Birmingham
- Addy Osmani, Learning JavaScript Design Patterns