-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsyntax.tex
505 lines (376 loc) · 38.6 KB
/
syntax.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
\chapter{Programovacie jazyky Dart a \JS{}}
\label{kap:jazyky} % id kapitoly pre prikaz ref
V tejto kapitole si povieme niečo o programovacích jazykoch Dart a \JS{}, s ktorými budeme počas celej práce robiť.
\section{Dart}
\label{sec:dart}
V tejto sekcii si predstavíme hlavné črty programovacieho jazyka Dart. Dart je objektovo orientovaný programovací jazyk. Je založený na definovaní tried, kde trieda môže dediť od najviac jednej inej triedy.
Jazyk Dart je voliteľne typovaný. (Túto vlastnosť si bližšie popíšeme v podkapitole \ref{subsec:typy}).
%(+ supports reified generics?).
Informácie do tejto kapitoly boli čerpané najmä zo špecifikácie jazyka \cite{DartLanguage}.
\subsection{Triedy}
Trieda (\emph{class}) definuje formu a správanie určitej množine objektov. Tieto objekty nazývame inštancie (\emph{instance}) danej triedy.
Trieda môže byť definovaná deklaráciou samotnej triedy alebo pomocou mixinov.
Trieda má konštruktory a členy (členy danej inštancie a statické členy). Členy sú metódy, premenné, gettery a settery.
%superclass
\paragraph{Nadtrieda}
Každá trieda má práve jednu nadtriedu (\emph{superclass}) okrem triedy \emph{Object},
ktorá nadtriedu nemá. Táto nadtrieda sa uvádza za kľúčovým slovom \emph{extends} alebo je
určená implicitne ako \emph{Object}. %with - mixin
Daná trieda dedí od nadtriedy všetky dostupné členy danej inštancie, ktoré neboli preťažené (\emph{override}).
%interface
\paragraph{Rozhranie}
Trieda môže implementovať (\emph{implements}) niekoľko rozhraní (\emph{interface}). Rozhranie definuje, ako by sa malo pracovať s objektom.
Má metódy, gettery, settery a množinu \uv{nadrozhraní}, ktoré rozširuje.
%Mixins
\paragraph{Mixin}
\label{par:mixins}
Mixin opisuje rozdiel medzi triedou a jej nadtriedou. Mixin je vždy odvodený od deklarácie existujúcej triedy.
Mixin môžeme použiť pri definovaní novej triedy pomocou kľúčového slova \emph{with M} (kde M je mixin).
Mixin je užitočný v prípadoch, kedy viacerým zdanlivo nezávislým triedam chceme pridať rovnakú funkcionalitu.
%abstract
\paragraph{Abstraktná trieda}
Trieda môže byť abstraktná, vtedy ju definujeme kľúčovým slovom \emph{abstract}. Takáto trieda nemusí mať implementované všetky metódy. Mixiny môžu byť abstraktné triedy. Abstraktná trieda nemá inštancie.
%constructor
\paragraph{Konštruktor}
Konštruktor triedy je špeciálna funkcia, ktorá vytvára inštanciu triedy. Volá sa rovnako ako trieda, ktorej prislúcha.
Ak nie je špecifikovaná, volá sa v implicitnom konštruktore konštruktor nadtriedy. % máme niekde generatíve constructors? (this.id)
% factory constructors? constant constructors?
Špeciálny typ konštruktora je \emph{factory}. Používa sa rovnako ako obyčajný konštruktor,
ale pri volaní konštruktora sa nevytvorí nová inštancia triedy hneď. Až počas vykonávania
tela konštruktora sa rozhodne, aká inštancia bude vytvorená/vrátená. (\emph{Factory} je
užitočné napríklad pri implementácii návrhového vzoru Singleton.)
\subsection{Typy}
\label{subsec:typy}
Programovací jazyk Dart podporuje voliteľné typovanie.
\paragraph{Statické typy}
Statické typy sú použité pri deklarovaní premenných, pri definícii návratových hodnôt funkcií a v ohraničení typu premenných.
Tieto statické typy sú použité iba pri statickej kontrole a v kontrolovanom móde. Na produkčný mód nesmú mať žiaden vplyv.
Medzi základné typy patria:
\begin{itemize}
\item konštanty (\emph{constants}): čísla (\emph{number}), booleovské premenné (\emph{bool}),
reťazce znakov (\emph{string}), nulový objekt (\emph{null}),
\item kolekcie viacerých prvkov: zoznamy (objekt \emph{List}), mapy (objekt \emph{Map}).
\end{itemize}
Pri produkčnom móde sa všetky typy nahradia jednotným typom \emph{dynamic}. Ten označuje neznámy typ.
\paragraph{Dynamic}
Typ \emph{dynamic} má definovanú každú možnú operáciu so všetkými možnými počtami parametrov. Návratová hodnota týchto operácií je vždy \emph{dynamic}. Chceme tak zabezpečiť, aby nám typ \emph{dynamic} nikdy nevrátil chybovú hlášku o nesprávnom type. \emph{Dynamic} je považovaný za typový objekt, aj keď to nie je trieda.
\paragraph{Void}
Typ \emph{void} možno použiť len ako typ návratovej hodnoty funkcie. \emph{Void} nie je považovaný za typový objekt. Môže oznamovať upozornenia v kontrolovanom móde, ak funkcia vracia inú hodnotu ako \emph{null}.
\paragraph{Null}
Rezervované slovo \emph{null} označuje \uv{žiadny} objekt. Je to jediná inštancia triedy \emph{Null}. Rozširovanie, implementovanie alebo použitie tejto triedy ako mixin spôsobí chybu pri kompilácii (\emph{compile-time error}).
Volanie akejkoľvek metódy na objekte \emph{null} spôsobí chybu.
\paragraph{This}%velmi divotvorna konstrukcia
Slovo \emph{this} označuje aktuálne používanú inštanciu triedy, s ktorou pracujeme. Statický typ \emph{this} je potom rozhranie tejto triedy.
%Slovo \emph{this} označuje cieľ vyvolania aktuálnej inštancie.
%Statický typ pre \emph{this} je rozhranie bezprostredne ohradenej triedy.
\subsection{Premenné}
Premenné sú úložiská v pamäti. Neinicializovaná premenná má hodnotu \emph{null}.
\emph{Static variable} je taká premenná, ktorá nie je asociovaná s konkrétnou inštanciou, ale s celou knižnicou alebo triedou.
\emph{Final variable} je taká premenná, ktorá je zviazaná s konkrétnym objektom od jej deklarácie. Spôsobuje \emph{static warning}, ak je inicializovaná aj v konštruktore. Spôsobuje \emph{compile-time errror}, ak nie je inicializovaná pri deklarácii.
\emph{Constant variable} je implicitne \emph{final}.
%opak final je mutable
Ak deklarácia nešpecifikuje typ premennej, tak je \emph{dynamic}, čo predstavuje neznámy typ.
\paragraph{Gettery a settery}
\label{par:getters}
Ku premenným pristupujeme pomocou prirodzených getterov a~setterov.
Getter je funkcia bez argumentov, ktorá v čase zavolania vyhodnotí
výraz, ktorý definuje danú premennú a vráti výsledok.
Setter je funkcia s jedným argumentom, ktorá danej premennej
priradí hodnotu jej argumentu. \emph{Final} premenné nemajú settery.
\subsection{Funkcie}
Funkcie predstavujú vykonateľné akcie. Funkcie pozostávajú z deklarácií, metód, getterov, setterov, konštruktorov. % a literálov.
Každá funkcia má 2 časti: deklarácia (signature) a telo (body). Popis funkcie obsahuje formálne parametre a môže obsahovať typ návratovej hodnoty. Telo funkcie môže mať 2 tvary:
\begin{itemize}
\item blok príkazov v zložených zátvorkách (\{ \ldots \}).
Ak tento blok príkazov neobsahuje príkaz \emph{return},
automaticky sa na koniec pridáva s návratovou hodnotou \emph{null},
\item \emph{=> e}, čo je ekvivalentné \emph{\{return e;\}}.
\end{itemize}
Oba bloky príkazov môžu byť vykonané syn\-chrónne (modifikátor \emph{sync*}) alebo asyn\-chrón\-ne (\emph{async, async*}). Bez modifikátora je blok príkazov vždy považovaný za syn\-chrón\-ny.
Každá funkcia má zoznam parametrov, ktorý obsahuje zoznam povinných pozičných
parametrov a zoznam voliteľných parametrov. Voliteľné parametre môžu byť
pomenované alebo pozičné, ale nie obe súčasne.
Ak sa neuvedie typ návratovej funkcie explicitne, jej typ je \emph{dynamic} alebo daná trieda, ak ide o konštruktor.
Externá funkcia (\emph{external}) je funkcia, ktorá má deklaráciu a telo funkcie na rôznych miestach v kóde. Môžu to byť napríklad funkcie implementované externe v inom programovacom jazyku alebo také, ktoré sú dynamicky generované, ale ich popis je statický a známy.
\subsection{Upozornenia a chyby}%warnings and errors
Dart rozlišuje niekoľko druhov chýb, napríklad:
\begin{itemize}
\item kompilačné chyby (\emph{compile-time errors}) teda chyby v čase kompilácie, ktoré
bránia ďalšiemu behu programu. Tieto musia byť nahlásené kompilátorom pred spustením
samotného chybného kódu,
\item statické upozornenia (\emph{static warnings}) sú chyby zistené statickou kontrolou (teda
nie za behu programu). Nemajú žiaden efekt v čase behu programu.
Statická kontrola sa týka najmä konzistentnosti typov, ale neznemožňuje kompiláciu ani beh
samotného programu. Statickú kontrolu by mali zabezpečovať vývojové prostredia a kompilátory.
\end{itemize}
\paragraph{Módy behu programu}
Programy môžu byť spustené v dvoch módoch:
\begin{itemize}
\item checked mode (\emph{kontrolovaný mód}) - v tomto móde fungujú \emph{static warnings} aj \emph{compile-time errors}. Je vhodný na písanie kódu a ladenie programu,
\item production mode (\emph{produkčný mód}) - ako samotný názov napovedá, tento mód je určený na beh programu u klienta. V tomto móde sa \emph{static warnings} nevyskytujú, sú tu len \emph{compile-time errors} a chyby, ktoré sa vyskytli priamo pri behu aplikácie.
\end{itemize}
\subsection{Súkromie}
Dart podporuje dve úrovne súkromia, \emph{private} (súkromný) a \emph{public} (verejný).
Objekt, ktorý je deklarovaný s kľúčovým slovom \emph{private} je súkromný, inak je každý objekt verejný.
Tiež môžeme definovať súkromný objekt tak, že jeho názov začína podčiarkovníkom (\glqq\_\grqq).
Programy v jazyku Dart sú organizované do knižníc. Objekt je dostupný v knižnici len ak je definovaný v danej knižnici, alebo ak je v inej knižnici \emph{public} a importovaný.
\subsection{Knižnice}
Program v jayzku Dart pozostáva z jednej alebo viacerých knižníc. Môže byť vytvorený z viacerých kompilačných jednotiek (\emph{compilation units}). Kompilačná jednotka môže byť knižnica alebo \emph{part}.
Knižnice sú jednotkami súkromia. Kód definovaný v rámci knižnice ako súkromný je dostupný len v rámci danej knižnice.
Knižnica pozostáva z množiny importov, exportov a verejne deklarovaných objektov. Tieto môžu byť triedy, funkcie alebo premenné.
\paragraph{Import}
Kľúčové slovo \emph{import} prepája knižnice. Určuje, ktoré knižnice môžu byť použité pri programovaní inej knižnice.
\emph{Import} umožňuje explicitne povedať, ktoré objekty z kategórie \emph{public} chceme skryť, tie uvedieme za kľúčovým \emph{hide}.
Alebo vybrať podmnožinu objektov, ktoré chceme ponechať (a ostatné sa nám skryjú) pomocou kľúčového slova \emph{show}.
Ak by sa nám mohlo stať, že názvy funkcií alebo premenných sa vo viacerých knižniciach prekrývajú (čo je problém a snažíme sa tomu zabrániť), môžeme premenovať dané objekty pomocou kľúčového slova \emph{as}.
Podobne sa dá pomenovať aj samotná knižnica, kde potom voláme prvky knižnice nasledovne: \emph{libraryName.objectName}.
\paragraph{Export}
Kľúčové slovo \emph{export} definuje množinu objektov, ktoré sú prístupné po importovaní danej knižnice L, v ktorej sa \emph{export} nachádza.
Môžeme exportovať množinu objektov alebo celú knižnicu.
Tiež môžeme obmedziť export knižnice pomocou \emph{show} a~\emph{hide} rovnako ako pri importovaní.
\paragraph{Parts}
Ak máme veľkú knižnicu, môžeme ju rozdeliť do viacerých súborov pomocou \emph{part} a \emph{part of}.
Všetky definície objektov, aj súkromné, sú medzi týmito časťami vzájomne viditeľné.
Hlavný súbor obsahuje kľúčové \emph{part}, kde pomenuje cestu k druhému súboru, ktorá reprezentuje časť knižnice. Tá pomenuje, ku ktorému hlavnému súboru prislúcha za~kľúčovým slovom \emph{part of}.
Importovanie ďalších knižníc potom stačí uviesť v hlavnom súbore.
\paragraph{Skripty}
\emph{Skript} sa nazýva knižnica, ktorá obsahuje funkciu \emph{main}. Takáto funkcia môže byť v jednom projekte práve jedna. Je to funkcia, ktorá predstavuje vstupné miesto programu.
\paragraph{Pub}
To, aby boli všetky knižnice, ktoré sú importované, dostupné a aktualizované, zabezpečuje špeciálny správca knižníc \emph{pub} (\emph{package manager}).
Každá knižnica má zoznam závislostí - aké verzie cudzích knižníc používa.
Pub vyžaduje špeciálny súbor (\emph{pubspec.yaml}) obsahujúci zoznam knižníc s požadovanými verziami ku každej knižnici. Na základe tohto súboru pracuje príkaz \emph{pub get}, ktorý stiahne potrebné zmeny.
Okrem iného spravuje \emph{pub} mená publikovaných knižníc, aby sa zabránilo kolíziám.
\subsection{Súbežnosť}%paralelizmus
Kód v jazyku Dart je vždy jednovláknový. Ak chceme vykonávať viac súbežných činností, používame špeciálnu entitu \emph{isolates}, ktorá má vlastnú pamäť a vlastnú kontrolu vlákna. Tieto entity medzi sebou komunikujú pomocou posielania správ, nezdieľajú žiaden stav.
Dart podporuje asynchrónnosť vykonávania programu. Kľúčovým \emph{await} odovzdáme kontrolu, pokým sa výraz za \emph{await} vyhodnotí. Ak sa nevie vyhodnotiť v čase vykonávania tejto inštrukcie, namiesto hodnoty sa vytvorí inštancia triedy \emph{Future}, za ktorú sa neskôr po dopočítaní dosadí daná hodnota výrazu.%neviem, či som to uplne dobre pochopila
Funkcia označená \emph{*} je \emph{generátor} (sync*, async*). \emph{Generátor} je funkcia, ktorá postupne vracia niekoľko hodnôt príkazom \emph{yield}. Pri ďalšom volaní \emph{moveNext} na generátore pokračuje program od posledného vykonaného \emph{yield} príkazu.
\subsection{Podpora v prehliadači}
Jazyk Dart nie je v bežných prehliadačoch podporovaný. Pri vyvíjaní prostredia existuje príkaz \emph{pub serve}, ktorý vytvorí server a transformuje kód z jazyka Dart do vykonateľného kódu v jazykoch JavaScript a HTML. Transformuje kód programom \emph{dart2js}. Takto vytvorený kód je možné ladiť v bežných prehliadačoch. Pri zmene kódu je nutné obnoviť stránku, na ktorej sa pretransformovaný kód spustí.
\emph{Dartium} je modifikácia prehliadača Chromium (open-source základ pre Google Chrome) s rozšírením pre jazyk Dart. To znamená, že pri použití prehliadača \emph{Dartium} nie je potrebné kód transformovať. Je určený pre vývoj aplikácií v jazyku Dart. V~produkcií však nie je odporúčaný. Do produkcie kód z jazyka Dart dostaneme príkazom \emph{pub build}.%asi? :)
\subsection{Syntaktické pomôcky}
\paragraph{Kaskádová notácia}
Kaskádová notácia má tvar \emph{e..sufix}, kde \emph{e} je výraz a \emph{sufix} je postupnosť operátorov, metód geterov alebo seterov na danom výraze. Táto konštrukcia je ekvivalentná \emph{(t)\{t.sufix; return t;\}(e)}.
Zaujímavé je jej použitie, keď môžeme na jednom objekte zavolať viacero metód za sebou bez toho, aby sme ju znova vypisovali. Pritom metódy, ktoré použijeme, nemusia mať návratovú hodnotu daný objekt. Príklad môžeme vidieť v ukážke \ref{lst:cascade} z~internetovej stránky o~jazyku Dart\cite{dartLanguageTour}.
\begin{lstlisting}[caption=Kaskádová notácia, label={lst:cascade}]
querySelector('#button') // Get an object.
..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
\end{lstlisting}
\section{\JS{}}
\label{sec:JS}
V tejto podkapitole si predstavíme hlavné črty programovacieho jazyka \JS{}.
JavaScript je objektovo orientovaný jazyk, ktorý upravuje internetové stránky v~prehliadači a vykonáva výpočty v prehliadači.
(Skriptovací jazyk je programovací jazyk zameraný na výpočty a manipuláciu s objektami už existujúceho systému.)
Dnes je to plne vybavený všeobecne navrhnutý objektovo orientovaný programovací jazyk.
Okolo tohoto programovacieho jazyka sa vytvorila veľká komunita, ktorá udržiava tento jazyk stále živý a veľmi používaný.
Organizácia {ECMA International®} definuje špecifikácie aj tohoto jazyka. V súčasnosti je najnovší \JS{}, inak sa označuje aj ako 7. edícía (ES7). V tejto práci sa špecifikujeme na túto verziu jazyka, aj keď spomenieme niektoré vlastnosti, ktoré ešte nie sú v špecifikácii, ale sa pripravujú do ďalšej verzie. Presnú špecifikáciu môžeme nájsť v literatúre \cite[\JS{}]{ECMAScript}.
Do tejto práce boli informácie o~JavaScript-e čerpané najmä zo série kníh \cite[You Don't Know JS]{youDontKnowJS1, youDontKnowJS2, youDontKnowJS3, youDontKnowJS4, youDontKnowJS5, youDontKnowJS6}.
Pomenovania JavaScript a ECMAScript (ES) sú pre tento jazyk ekvivalentné.
V~niektorých častiach práce spomíname konkrétnu verziu jazyka ES6, ktorá obsahuje veľa nových štruktúr oproti predošlým verziám.
\subsection{Triedy}
JavaScript má niektoré syntaktické prvky, ktoré sa spájajú s triedami, ako napríklad \emph{new}, \emph{class} alebo \emph{instanceof}. Avšak triedy ako také nemá. Na triedy sa môžeme pozrieť ako na návrhový vzor.
\paragraph{Objekty}
Všetko v JavaScript-e sú objekty, a teda aj trieda je objekt. Funkcie, ktoré sú volané s kľúčovým \emph{new}, sa bežne volajú konštruktory, aj keď v JavaScript-e nevytvoria štandardnú triedu ako v iných triedovo orientovaných jazykoch.
Ak hovoríme o inštancii triedy, myslíme tým kópiu daného objektu. Polymorfizmus na inštanciách triedy je opäť len výsledkom kopírovania vlastností. Preto aj odvodená trieda nemá odkaz na rodičovskú triedu, má od nej len nakopírované potrebné údaje.
\paragraph{Rozšírenia}
Mixin/extends pridáva špecifickú funkcionalitu z iného objektu. Pridáva ju kopírovaním. Avšak toto kopírovanie robí iba na prvej úrovni, teda ak hodnoty, ktoré sú ukladané pod kľúčmi, nie sú primitívne objekty, potom sú to objekty zdieľané referenciou. Čiastočne môžeme používať viacnásobné dedenie, ale nevyhneme sa kolíziám pri kopírovaní prvkov s rovnakým menom z viacerých zdrojov.
\paragraph{Prototype}
V JavaScript-e existuje možnosť, ako previazať objekty medzi sebou. Každý objekt má vlastnosť prototype (predvolená hodnota je na Object.prototype). Táto vlastnosť nám umožňuje používať funkcie, ktoré sme objektu nešpecifikovali explicitne (napríklad funkcia toString).
Pomocou prototype môžeme robiť dedenie, ktoré sa veľmi podobá tomu z tried. Prototype nekopíruje, ale robí odkaz na objekt \uv{kam sa pozeráme, keď nevieme, aký objekt máme použiť}.
Na programovanie v JavaScript-e sa však môžeme pozrieť aj ako na delegovanie správania medzi objektami namiesto dedenia medzi triedami.
\paragraph{Nový objekt}
Volanie funkcie s kľúčovým \emph{new} vytvorí nový objekt a vykoná telo funkcie. Funkcia, ktorá je volaná ako konštruktor, nie je ničím iná od obyčajnej funk\-cie a každá môže vytvoriť objekt.
Ak tejto funkcii pridáme prototype, budú ho mať všetky z nej odvodené objekty. Funkcia, ktorú nastavíme pre prototype, sa nekopíruje medzi ostatné objekty, ale je zdieľaná.
Ak chceme, aby program pridal link na iný objekt (prototype) za nás, môžeme namiesto kľúčového slova \emph{new} použiť funkciu \emph{Object.create(\ldots)}.
\paragraph{Triedy}
Hoci v JavaScript-e triedy ako také nie sú, od verzie ES6 existuje pre JavaScript aj kľúčové slovo \emph{class}, ktoré zaobaľuje prácu s prototypmi a snaží sa vytvoriť hierarchiu dedenia, ako majú triedovo orientované (\emph{class-oriented}) jazyky. Tiež podporuje \emph{extends} a \emph{super}, ako ich poznáme z iných jazykov.
\paragraph{}
O objektoch, ich prototypoch a rozšíreniach sa môžeme podrobnejšie dočítať v knihe \cite[this \& Object Prototypes]{youDontKnowJS3}.
\subsection{Typy}
Jazyk \JS{} nie je typovaný jazyk. Napriek tomu rozlišuje niekoľko základných typov, na ktorých má definované konkrétne operácie. Typy jazyka \JS{} sú \emph{Undefined}, \emph{Null}, \emph{Boolean}, \emph{String}, \emph{Symbol}, \emph{Number} a \emph{Object}. Každá hodnota premennej v tomto jazyku je charakterizovaná jedným z uvedených typov. V JavaScript-e nemajú typ premenné, ale hodnoty premenných, ktoré sú v nich uložené.
\begin{itemize}
\item \emph{Primitívne typy} sú string, number, boolean, symbol, null, undefined a object.
\item \emph{Objekty} sú ostatné typy. Každý primitívny typ má aj svoj objektový ekvivalent, na ktorom môžeme robiť operácie(napríklad zistiť dĺžku stringu). Funkcia je objekt, ktorý obsahuje aj vykonateľné príkazy. Ďalšie objekty sú napríklad Array, Date, RegExp alebo Error.
\end{itemize}
\paragraph{Objekty}
Objekty vieme definovať priamo, teda vymenovaním obsahu, alebo cez kľúčové \emph{new}. Obe metódy vytvoria rovnaký objekt. Všeobecne sa preferuje definovanie vymenovaním prvkov.
Obsah objektu môžeme plniť viacerými možnosťami, ako môžeme vidieť v ukážke \ref{lst:objekty}. Vymenovaním (riadok 4), cez~bodku (riadok 7 a 9) alebo cez~hranaté zátvorky (riadok 8 a 10). Platí, že keď používame bodkovú konvenciu, môžeme mená kľúčov nazývať iba jednoslovnými názvami bez medzier a špeciálnych znakov. Do~hranatých zátvoriek môžeme dať ľubovolný string vrátane medzier. Ak chceme použiť ako kľúč hodnotu premennej, musíme použiť hranaté zátvorky. Použitím rovnakého kľúča cez bodku aj v hranatej zátvorke sa dostaneme ku rovnakej hodnote.
\begin{lstlisting}[caption=tvorba objektu, label={lst:objekty}]
var objectString = new String("I am String");
var primitiveString = "I am primitive string";
var myObject = {
key1: 'value1';
}
myObject.key2 = primitiveString;
myObject["with space!"] = 'value2';
console.log(myObject.key1); // 'value1'
console.log(myObject["with space!"]); // 'value2'
\end{lstlisting}
\paragraph{Undefined} typ má práve jednu hodnotu \emph{undefined}. Každá premenná, ktorá nemá priradenú žiadnu hodnotu, ale je vytvorená, má práve túto hodnotu.
\paragraph{Null} typ má práve jednu hodnotu, \emph{null}. \emph{Null} predstavuje prázdny objekt. Od \emph{undefined} sa líši tým, že \emph{null} môže byť priradený ako hodnota do premennej.
\paragraph{This}
Kľúčové slovo \emph{this} má v JavaScript-e svoje špeciálne miesto. V iných jazykoch je to obvykle objekt, v ktorom sa nachádzame, definoval ho autor pri písaní kódu (author-time binding). V JavaScript-e je to objekt, ktorý volal náš objekt a je definovaný počas behu programu (runtime binding). \emph{This} ukazuje väčšinou na miesto, odkiaľ bola daná funkcia volaná. Keď sa pozrieme do zásobníka volaní, bude to funkcia, ktorá je hneď pred našou.
Pri určovaní hodnoty premennej \emph{this} sa používajú tieto štyri pravidlá:
\begin{itemize}
\item štandardné viazanie premennej this (\emph{default binding}) predstavuje miesto, odkiaľ bola funkcia volaná. V striktnom móde štandardné nastavenie this nefunguje,
\item implicitné viazanie premennej this (\emph{implicit binding}), ak voláme metódu na objekte v danom čase, this ukazuje na daný objekt,
\item explicitné viazanie premennej this (\emph{explicit binding}) vznikne použitím funkcie \emph{call()} alebo \emph{apply()}, kde ako prvý parameter dáme odkaz na \emph{this}, ktorý chceme využiť. Podskupinou je zviazanie napevno (\emph{hard binding}), kde spravíme wrapper okolo funkcie, ktorá nastaví hodnotu this na danú nemennú hodnotu určenú argumentom. Od verzie ES6 existuje metóda \emph{bind()} pre funkcie, ktorá robí \emph{hard binding},
\item viazanie premennej vytvorením nového objektu pomocou kľúčového slova \emph{new} (\emph{new binding}), vytvorí sa nová inštancia objektu, ktorá má v čase vykonávania this nasmerované na seba.
\end{itemize}
Špeciálne správanie majú \emph{arrow functions}, kde sa \emph{this} správa štandardne, ako to poznáme z iných programovacích jazykov. V takejto funkcii this odkazuje na seba.
O~funkciách v \JS{} si povieme viac v podkapitole \ref{subsec:JSfunctions}.
\paragraph{}
Podrobnejšie informácie o typoch môžeme nájsť v knihe \cite[Types \& Grammar]{youDontKnowJS4}, o~\emph{this} v~knihe \cite[this \& Object Prototypes]{youDontKnowJS3}.
\subsection{Premenné}
Premenné v JavaScript-e nemajú typ. Typ majú len hodnoty uložené v týchto premenných. Toto je veľký a často mätúci rozdiel oproti iným štandardným jazykom. Na typ hodnoty sa vieme pýtať príkazom \emph{instanceof}.
\paragraph{Deklarovanie premenných v \JS{}}
\JS{} podporuje primárne tri typy deklarovania premenných. Sú to \emph{var}, \emph{const} a \emph{let}.
V prípade \emph{const} a \emph{let} ide o premenné, ktoré sa nedajú deklarovať dvakrát s rovnakým menom a platia len v rámci daného bloku kódu. V štandardnej terminológii by sme ich mohli nazvať aj lokálne premenné.
Deklarovanie kľúčovým \emph{let} nám zabezpečí, že pôsobnosť premennej je iba v aktuálnom najmenšom bloku ohraničenom zátvorkami \emph{\{\}}. Užitočnosť \emph{let} môžeme vidieť napríklad aj v cykloch \emph{for(let i = 0, \ldots)\{\}}.
Na rozdiel od týchto, premennú \emph{var} môžeme deklarovať aj viackrát a môžeme sa na ňu pýtať aj mimo bloku, kde sme ju deklarovali. V ukážke \ref{lst:deklarovanie} vidíme viacnásobné deklarovanie, volanie premennej mimo bloku, kde bola zavolaná aj volanie premennej predtým, ako bola vytvorená. Tieto premenné by sme mohli nazvať aj globálne premenné.
Ak sa vyskytne v kóde premenná, kompilátor hľadá, kde bola definovaná. Ak ju nenájde, vytvorí novú premennú s daným menom ako globálnu. Ak beží tento skript v prehliadači, môžeme sa na túto premennú pozrieť aj ako na premennú daného okna a pristupovať ku nej nasledovne \emph{window.meno\_premennej}. (Takto v ukážke funguje premenná \emph{k}.)
Deklarovať môžeme aj viacero premenných naraz (riadok 12), alebo \uv{rozbaliť} objekt do premenných v jednom kroku (riadok 14).
\begin{lstlisting}[caption=JavaScript deklarovanie, label={lst:deklarovanie}]
var i = 2;
if (i >= 0) {
console.log( i, j ); // i = 2 , j = undefined
var j = 5;
var i = 3;
k = 10;
} else {
var j = 4;
}
console.log( i, j, k ); // i = 3 , j = 5 , k = 10
var a = 2, b;
var obj = {name:"foo", id:1};
var {name, id} = obj; // var name = obj.name, id = obj.id;
\end{lstlisting}
\subsection{Funkcie}
\label{subsec:JSfunctions}
Funkcia je špeciálny podtyp objektu, je to \uv{spustiteľný} objekt. Obsahuje kód, ktorý sa dá vykonať.
Do verzie ES5 boli všetky funkcie definované štandardne \emph{function foo(argumenty)\{ \ldots \}}.
Argumenty sú premenné, ktoré sú definované len v tele funkcie. Argumenty funkcie sú voliteľné a môžu byť pomenované. Tiež im môžeme pri~definovaní funkcie nastaviť nejakú preddefinovanú hodnotu.
Funkciu môžeme uložiť do premennej a pracovať s ňou ako s objektom.
Funkcia môže a nemusí mať svoje meno. Funkcia bez mena sa volá anonymná funkcia. Jej nevýhodou je, že sa na ňu nevieme odkazovať z tela funkcie a pri pozeraní zásobníka volaní funkcií nevieme, o akú funkciu sa jedná.
Špeciálny typ funkcie (od verzie ES6) je šípková funkcia (\emph{arrow function}). Primárnym motívom jej vzniku bolo zabezpečiť správanie \emph{this} premennej ako v iných programovacích jazykoch, teda aby smerovalo na túto funkciu.
Je to vždy anonymná funkcia. Vždy vystupuje ako výraz (nemá svoju deklaráciu). Má jednoduchú a krátku syntax, pred šípkou argumenty (ak je len jeden, môže sa vyskytovať bez zátvorky) a~za~šípkou výraz, ktorý funkcia vracia (bez kľúčového slova \emph{return}) alebo telo funkcie obalené kučeravými zátvorkami. Šípkové funkcie môžeme vidieť na malom príklade v~ukážke \ref{lst:arrow_func}.
\begin{lstlisting}[caption=šípkové funkcie, label={lst:arrow_func}]
var a = [1,2,3,4,5];
a = a.map( v => v * 2 ); // [2, 4, 6, 8, 10]
const sum = (x, y) => x + y;
sum(2, 5); // 7
var div = (x, y) => {
if (y != 0) {
return x/y;
} else {
return Infinity;
}
}
\end{lstlisting}
\subsection{Upozornenia a chyby}
\paragraph{Striktný mód} je cesta, ako sa priblížiť kontrolovanému módu v JavaScript-e. Úmyselne má mierne inú sémantiku niektorých príkazov. Medzi najväčšíe rozdiely medzi striktným a štandardným módom patria tieto vlastnosti:
\begin{itemize}
\item niektoré tiché chyby mení na chybové hlášky (pomocou kľúčového slova \emph{throws}),
\item zabraňuje niektorým chybám, aby stroj, ktorý kompiluje a vykonáva kód, mohol lepšie optimalizovať vykonávanie programu,
\item zakazuje niektoré syntaktické konštrukcie (napríklad definovať viackrát rovnakú premennú alebo priradiť hodnotu neexistujúcej premennej),
\item pridáva nové rezervované slová (implements, interface, let, package, private, protected, public, static, and yield).
\end{itemize}
Striktný mód vieme zapnúť pre celý skript alebo len pre konkrétnu funkciu. Zapína sa príkazom \emph{'use strict';} na začiatku funkcie/skriptu.
Striktný mód je podporovaný rôzne rôznymi prehliadačmi. Kód, ktorý píšeme v striktnom móde, by mal byť vykonateľný aj v štandardnom móde. Viac o striktnom móde sa môžeme dočítať na stránke \emph{Mozilla Developer Network} \cite{strict}.
\paragraph{Spracovanie chýb s premennými\\}
Priradenie hodnoty neexistujúcej premennej:
\begin{itemize}
\item ak je vykonávanie v štandardnom móde, premenná sa vytvorí ako globálna a~priradí sa jej daná hodnota,
\item ak je v striktnom móde, globálnu premennú nevytvorí, ale vyhodí chybu typu \emph{ReferenceError}.
\end{itemize}
\emph{TypeError} znamená, že sme na existujúcom objekte chceli vykonať nelegálnu alebo neuskutočniteľnú akciu.
\subsection{Súkromie}
\JS{} nemá rôzne úrovne súkromia. V JavaScript-e sú dve úrovne platnosti premenných. Jednou je funkcia a druhou celý súbor. Verejné objekty z daného súboru sú len tie, ktoré sú označené kľúčovým slovom \emph{export} alebo \emph{export default}. Ostatné sú súkromné. Vo funkcii sú všetky objekty súkromné, ak ich nevrátime v objekte ako návratovú hodnotu z funkcie.
\subsection{Knižnice}
Do verzie ES5 bol kód delený do modulov. Od verzie ES6 JavaScript poskytuje možnosť importovať a exportovať súbor alebo knižnicu.
Zo súboru môžeme exportovať najviac jeden objekt predvolene (\emph{export default} foo). Ostatné môžeme exportovať ako pomenované (\emph{export} bar).
Iba tie objekty, ktoré exportujeme, môžeme vidieť z iných súborov.
Môžeme exportovať aj všetky objekty naraz (\emph{export *}), alebo exportovať objekty z inej predtým importovanej knižnice (\emph{export * from 'baz';}).
Ak chceme používať objekt z iného súboru, musíme ho importovať. Ak importujeme predvolene exportovaný objekt, jeho meno nedávame do zátvoriek.
Každý iný objekt ale musí byť v kučeravých zátvorkách (
\emph{import defaultObject, \{obj2, obj3\} from 'baz';}).
Môžeme importovať aj všetky objekty z danej knižnice, avšak potom musíme poskytnúť meno, pod ktorým budeme ku objektom pristupovať (\emph{import * as FOO from 'foo';}).
\subsubsection{Dostupnosť}
Pre jazyk \JS{} je dostupné množstvo knižníc. Veľká časť z nich je dostupná cez správcu \emph{npm}. Vkladanie knižnice do projektu je veľmi jednoduché volanie príkazu \emph{npm} s vhodnou kombináciou prepínačov. (Volanie funkcie z priečinka projektu s prepínačom \emph{--save} bolo u nás postačujúce.)
\subsection{Súbežnosť}
Pri programovaní webových aplikácií potrebujeme písať asynchrónny kód (napríklad dotazy na server). Nemôžeme si dovoliť čakať na odpoveď, ktorá trvá dlho (a ani nevieme, či príde). Potrebujeme reagovať na používateľa.
JS beží v prehliadači, on rozhoduje o tom, čo je kedy vykonané, často je kód vykonaný sekvenčne (za sebou), nie paralelne.
\paragraph{Callback a Promise}%TODO preložiť?
\emph{Callback} (spätné volanie) je funkcia, ktorá sa zavolá, keď sa daný kód vykoná. \emph{Callback} nie je úplne spoľahlivé riešenie. Preto potrebujeme nástroj, na ktorý sa môžeme spoľahnúť.
\emph{Promise} (prísľub) vykonáva asynchrónny kód.
\emph{Promise} je typ objektu, ktorý nám sľubuje, že keď sa dokončí kus asynchrónneho kódu, hodnota \emph{promise} sa doplní vypočítanou.
Je \emph{thenable}, čo znamená, že na ňom môžeme zavolať metódu \emph{then}, ktorá sa vykoná vtedy, keď sa naplní \emph{promise}. Poskytuje nám spôsob, ako spracovať neúspešný pokus o vykonanie kódu.
Podobne ako \emph{then} použijeme \emph{catch} funkciu, ktorá odchytí chybovú hlášku, ak nejaká nastala. Malo by platiť, že vždy sa vykoná vetva \emph{then} alebo vetva \emph{catch}. Jednoduché použitie tejto štruktúry vidíme v~ukážke \ref{lst:promise}.
Alternatívne môžeme definovať \emph{promise} s jednou funkciou, ktorá spracuváva aj úspešný aj neúspešný výsledok (\emph{new Promise(function(resolve, reject)\{\ldots\})}).
\emph{Promise} sa nevyhýba callbackom, ale vhodne ich zaobaľuje, aby sa s nimi spoľahlivo pracovalo.
\emph{Promise} vie čakať na viac hodnôt (\emph{Promise.all([\ldots])})
alebo na prvú z množiny (\emph{Promise.race([\ldots])}).
Promises môžeme reťaziť za sebou. To nám pomáha rozmýšľať nad asynchrónnymi operáciami sekvenčne.
\begin{lstlisting}[caption=Promise, label={lst:promise}]
const promise = fetch(serverUrl);
promise
.then(response => console.log("response: ", response))
.catch(error => console.log("error: ", error));
\end{lstlisting}
\paragraph{Generátory}
\emph{Generátor} je funkcia, ktorá generuje niekoľko hodnôt a možno cez tieto hodnoty iterovať. Ku jednotlivým hodnotám sa dostaneme cez volanie funkcie \emph{next()} na danom generátore.
Je to špeciálna funkcia, ktorá obsahuje niekoľko volaní \emph{yield}, ktoré pozastavia vykonávanie funkcie a voliteľne vrátia hodnotu ako argument tohoto volania.
Ak chceme pokračovať vo vykonávaní tejto funkcie, zavoláme na generátore funkciu \emph{next()} s voliteľnými argumentami, ktoré sa potom do kódu doplnia namiesto kľúčového slova \emph{yield}.
V ukážke \ref{lst:generator} vidíme volanie generátora, volanie s argumentom aj \emph{yield} s návratovou hodnotou.
\begin{lstlisting}[caption=Generátor, label={lst:generator}]
var it = function *foo(){
let a = 1;
a += yield a;
yield a;
return a*a;
}
it.next(); // spusti funkciu od zaciatku, 3. riadok vrati 1
it.next(2); // do riadku 3 sa namiesto yield doplni 2, 4. riadok vrati 3
it.next(); // return vrati poslednu hodnotu (9) a nastavi flag done=true
\end{lstlisting}
\emph{Generátor} môžeme využiť pri vykonávaní asynchrónneho kódu, napríklad keď čakáme na odpoveď zo servera. Hlavná funkcia \uv{\emph{yield}-ne} request na server a keď je hotový, hlavná funkcia bude zavolaná a do nej doplnená odpoveď cez argument funkcie \emph{next()} (hlavná funkcia sa správa ako generátor).
\paragraph{Async a Await}
Štruktúry, ktoré nepatria do špecifikácie \JS{}, ale mali by byť v nasledujúcich verziách (pripravuje sa špecifikácia ôsmej edície), sú \emph{await} a \emph{async}.
Tieto štruktúry schovávajú prácu s \emph{promise}-mi a \emph{generátor}-mi a uľahčujú logiku volania asyn\-chrón\-nych funkcií.
\emph{Async} označuje funkciu, ktorá je vykonávaná asyn\-chrón\-ne, a môže obsahovať volanie \emph{promise}, na ktorý treba čakať.
Kľúčové slovo \emph{await} označuje miesto volania asyn\-chrón\-neho kódu. Pri použití \emph{await} sa vykonávanie funkcie pozastaví a čaká sa na dokončenie \emph{promise}, ku ktorému patrí.
Podrobnejšie sú popísané na stránkach \emph{Mozilla Developer Network} \cite{async, await}.
\paragraph{Web Workers}
JavaScript je jednovláknový jazyk. Niektoré prehliadače však poskytujú nástroj (\emph{Worker}), ako vykonávať úlohy vo viacerých vláknach paralelne (\emph{task paralelism}). Tento nástroj sa v praxi používa na vykonávanie ťažkých matematických operácií, prácu a triedenie veľkých dát alebo spravovanie veľkého množstva komunikácie.
\paragraph{}
Viac o asynchrónnom programovaní sa môžeme dočítať v knihe \cite[Async \& Performance]{youDontKnowJS5}.
\subsection{Podpora v prehliadači}
JavaScript ako skriptovací jazyk je vykonávaný prehliadačom (správanie prehliadačov sa môže mierne líšiť). Spoločnosť \emph{ECMA International} definuje štandardy tohoto jazyka. Podpora pre tieto štandardy rastie, ale nie je ešte úplná \cite{podporaES7}.
Z toho dôvodu sú novšie verzie prekladané do niektorej staršej (napríklad verzia ES5 má vysokú podporu). Na to slúžia kompilátory ako napríklad \emph{Babel}. Jazyk \JS{} má potenciál bežať v budúcnosti na prehliadačoch bez potreby kompilácie.
\subsection{Syntaktické pomôcky}
\paragraph{Rozširovací/zvyškový operátor}
\label{par:spreadOp}
ES6 pridáva nový operátor ``\emph{...}''. Podľa kontextu, v ktorom sa nachádza, môže byť:
\begin{itemize}
\item zvyškový (\emph{rest}) operátor - pri definovaní funkcie nám umožňuje zadať ľubovolný počet argumentov v hlavičke funkcie. Definuje štandardne vymenované, plus tie zvyšné. Tie zvyšné potom umiestni do poľa. Sprehľadňuje definovanie funkcií a~vyhýba sa riešeniu \emph{arguments} z predchádzajúcich verzií JavaScript-u,
\item rozširovací (\emph{spread}) operátor - umožňuje iterovateľný objekt rozbaliť a nakopírovať do jednotlivých položiek tohoto objektu. Nahrádza napríklad funkcie \emph{apply} a~\emph{concat} na poli prvkov. Tiež umožňuje zavolať funkciu s argumentami z iterovateľného objektu jednoduchým spôsobom.
\end{itemize}
Názorné použitie tohoto operátora možno vidieť v ukážke \ref{lst:...}.
Informácie boli čerpané z knihy \cite[Exploring ES6]{expES6}.
\begin{lstlisting}[caption=rozširovací/zvyškový operátor, label={lst:...}]
function foo(x, y, ...z){ // rest
console.log(x, " ", y); // 1 2
console.log(z); // [3, 4, 5]
}
foo(1, 2, 3, 4, 5);
var arg1=[a1, a2], arg2=[a3, a4]; // spread
var con = [...arg1, ...arg2]; // [a1, a2, a3, a4]
foo([...arg1]); // a1 a2
\end{lstlisting}
%TODO skontroluj veľké a malé písmená na začiatkoch názvov
%TODO skontroluj anglické/slovenské pomenovania
%TODO skontroluj listingy ako vychadzaju na stranu
\section{Porovnanie jazykov Dart a \JS{}}
Vlastnosti programovacích jazykov Dart a \JS{} zhrnieme v tabuľke \ref{tab:compare}.
\input tabulkaPorovnania.tex