title |
---|
Fyrirlestur 13.3 – JavaScript upprifjun |
Ólafur Sverrir Kjartansson, osk@hi.is
JavaScript er túlkað skriftumál, byggt á prótótýpum með dýnamískar, veikar týpur, fyrsta flokks föll og stuðning við hlutbunda-, gildinga- og fallaforritun
Mörg atriði eru ólík, en það sem skiptir mestu máli í fyrstu:
- Java er þýtt en JavaScript er túlkað
- JavaScript kóði er túlkaður í hverri keyrslu
- Breytur í Java hafa týpu, gildi í JavaScript hafa týpu
- Höfum aðgang að JavaScript túlk vafra í gegnum DevTools
- Opnum DevTools og förum í
console
og skrifum skipanir og forrit
- Opnum DevTools og förum í
- Node.js er líka með JavaScript túlk, getum keyrt með
node
í terminal
Breytur í JavaScript hafa ekki týpu, gildi hafa týpu:
number
,string
boolean
,undefined
,function
eðaobject
- Scientific notation:
1.25e6 // 1.25 * 10^6 = 1250000
Infinity
og-Infinity
– gildi sem geta komið upp í útreikningum9e999 // Infinity
1/0 // Infinity
NaN
– „Not a number“, skilað þegar ekki er hægt að reikna0 / 0 // NaN
1 - 'a' // NaN
- Skilgreinum strengi innan
'
eða"
'Halló, heimur!'
eða"Halló, heimur!"
- Notum
\
til að escapea sérstaka stafi eða sérstök tákn (t.d. newline eða tab)"Halló, \"heimur\""
true
eðafalse
- Notum oft í flæðistýringu þegar við berum saman gildi
- Höfum aðgang að hjálparföllum sem leyfa okkur að vinna með strengi og tölur
- Eru partur af umhverfinu
isNaN()
,isFinite()
,parseInt()
o.fl
- Gildi á breytum sem ekki hafa verið skilgreindar
- Gildi á eigindum hluta sem ekki hafa verið skilgreindir
typeof baz // "undefined"
- Gildi sem stendur fyrir að vísvitandi fjarveru gildis
- Getum lent í að fá null reference villur ef við höldum að eitthvað sé ekki null
null.length
Uncaught TypeError: Cannot read property 'length' of null
- Þegar við notum gildi getur þeim verið kastað óbeint
- Svipað og
(int)foo
í Java og C nema óbeint
- Svipað og
- Reglur um hvernig þeim er kastað, type coercion
- Fáum ekki týpu villur á keyrslutíma
- Type coercion þvingar týpur til að spila saman
- Reglur skilgreindar í spec en geta komið manni á óvart
- Getum athugað hvort tölur eða strengir séu minni eða stærri en aðrir
3 > 2 // true
'foo' > 'bar' // false
- Samanburður á strengjum er ekki „réttur“, stór stafur er alltaf „minni en“ lítill o.fl.
- Höfum jafnt eða stærra
>=
og jafnt eða minna<=
virkja - Fyrir jöfnuð og ójöfnuð höfum við
!=
,==
,!==
,===
- Samanburður með
==
og!=
mun byrja á að kasta báðum gildum - Samanburður með
===
og!==
mun byrja á að bera saman týpur og passa uppá að þær passi (eða ekki)- Notum fyrir allan samanburð!
- Þegar við erum með hluti sem haga sér eins og
boolean
án þess að vera það, tölum við um að þeir séutruthy
eðafalsy
- Byggir á type coercion
false
0
'' // tómi strengur
null
undefined
NaN
- Allt sem er ekki falsy
null
ogundefined
eru ekki jöfn neinu nema sjálfu sérNaN
er ekki jafnt neinu, ekki einu sinni sjálfu sér
- Getum unnið með boolean gildi með
and
,or
ognot
virkjum &&
erand
virkji sem er tvístæður og skilartrue
þá og því aðeins að bæði stök séutrue
, annarsfalse
true && false // false
true && true // true
||
eror
virkji sem er tvístæður og skilartrue
ef annað gildi ertrue
true || false // true
false || false // false
!
er neitunarvirkji, kastar segð úrtrue
ífalse
og öfugt!true // false
- Virkar fyrir öll gildi út af truthy og falsy
- Segð er kóðabútur sem skilar gildi
- Tala, stengur o.fl.
- Segðir geta innihaldið aðrar segðir
1 + 1
- Skipanir eru samansöfn af segðum
- Forrit eru samansöfn af skipunum
- Einfaldasta skipunin (og segðin, og forritið) er segð með semíkommu
1;
- Semíkomma er statement terminator einsog í Java eða C
- Ekki krafa, Automatic Semicolon Insertion sér um að setja inn ef sleppt
- Þarf að passa, við ættum alltaf að setja inn semíkommu
- Skilgreinum breytur með lykilorðunum
let
,const
eðavar
let foo;
- Getum aukalega gefið gildi úr segð
let foo = 'bar';
const FOO = 1; // breytunöfn eru hástafanæm
Þar sem breytur í JavaScript hafa ekki týpu getum við breytt gildum þeirra.
let a = 'halló heimur';
a = 1;
a = false;
a = undefined;
- Þegar við keyrum JavaScript forritin okkar gerist það í ákveðnu umhverfi
- Ekki tómt, inniheldur staðlaða hluti og föll sem eiga við umhverfið
- Í vafra höfum við aðgerðir t.d. til að eiga við vefsíðuna, bundið við window
- Í node.js höfum við aðgerðir t.d. til að eiga við skráarkerfið, bundið við process
- Höfum aðgang að flæðistýringum og lykkjum
- líkjast mjög mikið þeim sem eru í Java
- Stýrum flæði forrita og framkvæmum ítranir
- Í lykkjum getum við notað:
break
til að brjótast út/hætta í lykkjucontinue
til að sleppa rest af lykkju og halda áfram í næstu
while
ogdo .. while
lykkjur leyfa okkur að endurtaka kóða svo lengi sem einhver segð er sönndo .. while
mun alltaf keyra kóða einu sinni áður en segð er athuguð
for
lykkjur eru sérhæfðari og nýta mjög algent form á lykkjum:- Setja byrjunargildi
- Athuga núverandi gildi
- Uppfæra gildi
- Ef við höfum kóða sem notar
if
ogelse if
mikið getum við notaðswitch
- Blokkir af kóða sem geta haft nafn
- Notum til að skipuleggja kóða og draga úr endurtekningu
- Engar eða fleiri færibreytur (viðföng, argument)
- Hugsanlega með skilagildi, skilgreindu með
return
- Ef ekki skilar fall
undefined
- Ef ekki skilar fall
- Hlutir einsog flest annað og geta því verið gildi breytu
- Ef við skilgreinum fall með
function
án þess að binda við breytu - Getum kallað í áður en skilgreint
- Öll föll eru fundin áður en forrit er keyrt og þ.a.l. aðgengileg
- Breytur eru skilgreindar með lexical scope per fall
- Breytan er aðeins aðgengileg innan falls
- En aðeins ef breyta er skilgreind með
let
,const
eðavar
- Ef ekki er breytan sett í global scope
- Getur valdið leiðinlegum böggum
- Breytur skilgreindar utan falla eru í global scope
- Áður en
let
ogconst
voru skilgreind var aðeinsvar
var
er skilgreint fyrir global scope eða lexical scope fallslet
ogconst
eru skilgreind fyrir block, eru block scoped
- Stuttur syntax fyrir föll með fat arrow:
() => {}
- Megum sleppa sviga ef ein færibreyta
- Skila gildi ef eitt statement, annars
return
- Við getum bundið föll við breytur án þess að gefa þeim nöfn
- anonymous function
- Þar sem föll eru gildi getum við líka skilað föllum úr föllum
- Færibreytur á föllum hafa ekki týpur heldur gildið
- Fall getur því tekið inn færibreytur sem geta verið hvaða gildi sem er
- Primitives eru pass by value
- Objects eru pass by reference
- Getum skilgreint föll sem taka óskilgreindan fjölda af færibreytum
- variadic function
- Getum skilgreint föll innan fall
- Innri föll eru aðeins í scope fyrir ytra fall
- Innri föll hafa aðgang að scope ytra falls
- Þegar við höfum innri föll þá myndum við lokun um umhverfi þess
- Innra fall hefur aðgang að ytra scope meðan það lifir
- Breytu nöfn í innriföllum skrifa yfir ytri
- Fylki leyfa okkur að safna hlutum í raðaða lista
- Búum til array með
[]
const list = [];
- Nálgumst gildi innan fylkis með bracket notation
- Nálgumst eftir index, byrjar frá 0
array[0]
nálgast fyrsta stak í index 0,array[1]
annað stak í index 1 o.s.fr.
length
skilar fjölda staka í fylki, frá 0 til stærsta index
- Næstum öll JavaScript gildi hafa property (eigindi)
'foo'.length
,Math.min()
- Öll nema
null
ogundefined
- Property nálgumst við með:
.
– dot notation['foo']
– bracket notation
- Byrjum á að hugsa um object í JavaScript sem geymslu fyrir gildi þar sem gildi á sér nafn
- Skilgreinum með
{}
, innan þess skilgreinum við eigindi hluts meðheiti: gildi
- Ef heiti er óleyfilegt breytunafn skilgreinum við sem streng
gildi
eru öll leyfileg gildi
- Eigindi eru oftast skilgreind eitt per línu til að auka lesanleika
- Seinasta eigindi má hafa kommu á eftir sér, kallað trailing comma
- Ef við biðjum um eigindi sem ekki er skilgreint á hlut fáum við
undefined
- Mjög ólíkt
object
í Java
- Ef við skilgreinum parameter í falli með
...
fyrir framan er það rest parameter- (parameter er skilgreiningin, argument er raun gildið sem sent er inn)
- Inniheldur rest af argumentum þegar kallað er í fallið
- Ef við notum
...
fyrir utan parameter í föllum kallast það spread operator - Dreifir úr breytu
- Getum dreift úr
string
ogarray
, ekkiobject
,number
og öðrum gildum
- Niðurbrot á fylkjum og hlutum í breytur
- Virkar einsog maður myndi halda, dreifir úr hlutum í þær breytur sem maður vill
- Getum skilgreint sjálfgefin gildi
- Fáum
undefined
ef ekkert gildi passar, ekki villu
- JavaScript hefur stuðning við
try catch
eðaexceptions
- Kóði getur kastað villum: innbyggðum og okkar eigin
- Grípum villur og gerum eitthvað í þeim
- Köstum villu með
throw
- Notum
Error
, innbyggðan hlut sem heldur utan um villur throw Error('villa');
- Notum
- Fáum stacktrace með villum, hvaðan þær koma upp
- Ef við grípum ekki villu flýtur hún upp þar til hún veldur usla á efsta lagi
- Í versta falli stoppar keyrslu
- Getum gripið villur og gert eitthvað við þær með
try catch
- Höfum stuðning við reglulegar segðir í JavaScript
- Skilgreinum mynstur sem er borið saman við texta til að vinna með hann
- Kraftmikið, flókið og oft óskiljanlegt
- Þegar við vinnum með forrit er þeim yfirleitt skipt upp í einingar
- Safnar saman virkni á einum stað, inniheldur föll og breytur
- Skilgreinum API (Application Programming Interface) fyrir einingu
- Einfaldar að hugsa um forritið, ákveðin eining gerir ákveðin hlut
- Getur hjálpað við að stýra flækjustigi
- Þurfum ekki að „halda öllu forritinu í hausnum“ í einu
- Skilgreinum namespace, minnkar líkur á að við skemmum fyrir öðrum eða aðrir skemmi fyrir okkur
- Sérstaklega í JavaScript með global og local scope
- Ýtir undir endurnýtingu á kóða
- Getur verið flókið að ákveða hvernig og hvenær skipta eigi forriti upp
- Að skrifa gott API er erfitt
- Lærum hægt og rólega með því að skrifa sjálf og nota önnur forritasöfn
- Eða IIFE, „iffy“
- Sjálfkeyrandi nafnlaus föll
- Býr til fall sem heldur hlutum utan global scope
- Notað til að búa til einingar í JavaScript
- Nýtir lokun til að einangra forritið okkar
- Aðeins nafnið á einingu í global scope, ekki öll föll eða allar breytur
- Skilum hlut sem skilgreinir API forrits
- Þegar forritin okkar fara að nýta hluti sem eru ekki í minni þurfum við að beita öðrum aðferðum í forritun
- Það er hratt að sækja hluti í minni, hægara að sækja á disk og (oftast) enn hægara að sækja yfir net
- Bíðum ekki eftir því að beiðni klárist, nýtum ósamstillta forritun (asynchronous/async programming)
- Forrit sem þið hafið séð hingað til eru samstillt—þau keyra eina línu í einu, eitt fall í einu—eru línuleg
- Hægt að nota þræði, JavaScript hefur ekki stuðning við þá
- Notum async forritun með event loop á einum þræði
- Höldum CPU ekki uppteknum á meðan beðið
- Ein leið til að vinna með async kóða
- Köllum í fall sem tekur langan tíma með callback argument
- Fallið kallar í callback fall með niðurstöðu þegar búið
- Ef við köllum í annað fall sem tekur langan tíma úr callback þurfum við annað callback o.s.fr. o.s.fr.
- Leiðir í JavaScript til að búa til föll sem keyra í framtíðinni
setTimeout(callback, delay)
kallar ícallback
fallið eftirdelay
millisekúndursetInterval(callback, interval)
kallar ícallback
áinterval
millisekúndu fresti
- Hjúpun fyrir gildi sem mun verða til í framtíðinni
- Gerir asynchronous forritun auðveldari
- Flóknara hugtak en callbacks
- Þegar við skilgreinum Promise köllum við í:
resolve
með gildi þegar við höfum lokið aðgerðreject
með villu þegar eitthvað fer úrskeiðis
- Þegar við vinnum með promise skilgreinum við
then
callback til að vinna með gildið, fær gildi sem argumentcatch
callback til að vinna með villu, fær villu sem argument
then
ogcatch
eru föll á Promise- Getum sent promise gildi á milli!
Í æskilegri röð:
<script src="scripts.js"></script>
- Innan
<script>...</script>
- Forðast að binda JavaScript við element með on* attributes (t.d.
onclick
)
HTML, CSS og JavaScript er ekki sótt á augabragði, í einfaldaðri mynd gerist:
- HTML er sótt
- HTML er þáttað
- Hvert
<script>
er sótt, þáttað og keyrt
- Hvert
<link rel="stylesheet">
er sótt og þáttað - HTML þáttun líkur
- Síða er teiknuð
- Document Object Model
- Leyfir forritum og skriptum að gera dýnamískar breytingar á efni, skipulagi og útliti skjala (oftast HTML eða XML) gegnum API
- Hlutlaust á platform og mál
- Staðlað af W3C
- Stendur fyrir gluggann sem inniheldur DOM tréð
- Umhverfið sem forritin okkar eru keyrð í
- Heldur utan um global scope
- Hver gluggi eða tab í vafra hefur eigin
window
- Nálgumst DOM í gegnum
document
hlutinn áwindow
- Hvert element er nóða (node) í DOM tré
nodeType
segir til um gerð nóðu, t.d.1
erELEMENT_NODE
og3
erTEXT_NODE
- Fastar skilgreindir á
Node
, t.d.Node.ELEMENT_NODE
Hver nóða hefur vísanir í foreldri, börn og systkini:
parentNode
– foreldri nóðuchildNodes
– fylki af börnum nóðu, ef nóða erlastChild
– seinasta barn nóðupreviousSibling
– fyrra systkini nóðu- o.fl.
- Oftast þurfum við að finna ákveðin element, ekki ítra gegnum þau öll
document
og element hafa föll sem leyfa okkur að leita eftir ýmsum leiðum
- Leitar eftir CSS selector að fyrsta elementi sem passar (dýpt fyrst)
document.querySelector('.important')
til að leita á allri síðuelement.querySelector('.important')
til að finna undir ákveðnuelement
- Þegar við leitum í trjám er tvennt í boði:
- Dýpt first (depth first), farið eins djúpt og hægt er á grein áður en næsta grein er skoðuð
- Breidd fyrst (breadth first), farið eins breitt og hægt er áður en farið er að skoða börn greinar
- Leitar eftir CSS selector að öllum elementum sem passar
- Skilar statsískum
NodeList
, ekki lifandi document.querySelectorAll('div')
til að leita á allri síðuelement.querySelectorAll('div')
til að finna undir ákveðnuelement
document.createElement(element)
– býr til nýtt element sem við getum átt viðdocument.createTextNode(text)
– býr til texta nóðu- Notum síðan föll á node til að bæta við DOMið, t.d.
appendChild
- Við getum breytt CSS beint á elementi
- Höfum aðgang að
style
hlut á nóðu,node.style
- Yfirleitt viljum við ekki gera það
- Bókstaflega setur stíla á element einsog með
style
attribute
- Bókstaflega setur stíla á element einsog með
- Betra að breyta því hvaða
class
eru á element
- Þegar við skrifum flóknari forrit tökum við yfirleitt við skipunum eða gögnum frá notendum
- Hvernig getur forritið okkar vitað þegar slegið er á takka eða ýtt á músarhnapp?
- Sífellt að athuga hvort búið sé að hreyfa mús eða smella á takka? 😫
- Notum atburði (events) til að bregðast við hlutum sem gerast á einhverjum tímapunkti í framtíðinni
- Atburðir gerast ósamstillt—eru async!
- Getum fylgst með atburðum...
- sem vafrinn veldur
- sem notandi veldur
- Skráum þáttöku með
addEventListener
falli á nóðum
- Skráum að við viljum meðhöndla vissa tegund af atburð á ákveðnum nóðum
- Þegar atburður gerist eru allir þeir sem skráð sig hafa látnir vita í (flestum tilfellum) FIFO (first–in, first–out) röð
- Aðeins ein meðhöndlun á sér stað í einu
- Fáum hlut með upplýsingum um atburð sem argument í fall
- Oftast kallað
e
eðaevent
- Oftast kallað
- Upplýsingar eru t.d. um hvaða lykil var slegið á lyklaborð, eða hvaða takka á mús
- [Búið til af Tim Berners-Lee](Búið til af Tim Berners-Lee) í sambandi við HTML
- Fyrst skjalað sem útgáfa 0.9 1991
- RFC 1945 skilgreinir HTTP 1.0 árið 1996
- RFC 2616 skilgreinir HTTP 1.1 árið 1999
- HTTP byggir á request—response milli client og server
- Client sendir request á server
- Server framkvæmir aðgerðir og sendir response á client
GET
– biður um síðu, lang mest notaða aðferðin!POST
– Biður server um að taka við gögnum í request sem nýrri einingu. T.d. nýtt svar við umræðuþræði eða ný gögn í gagnagrunni
- Sendir bæði í request og response
- Heiti og gildi í texta, aðskilið með tvípunkt
Connection: close
Þegar þjónn svarar með response gefur hann upp stöðukóða, sem tölu og lesanlegan texta
1xx
– Til upplýsinga2xx
– Gekk, success3xx
– Áframsending, redirection4xx
– Villa hjá client5xx
– Villa hjá server
- Skilgreint í RFC 3986
- Uniform Resource Identifier – strengur sem skilgreinir auðlind
- Með nafni, staðsetningu eða bæði
- Auðlind er einhver eining sem við viljum nálgast, t.d. HTML skjal, mynd
- JavaScript Object Notation
- Létt gagna format sem er auðvelt að lesa og skrifa, bæði fyrir menn og vélar
- Byggir á almennum gagnastrúktúrum
- Heiti/gildi pörum (objects, dictionary, hash table o.s.fr.)
- Röðuðum listum (array, vector o.s.fr.)
- Asynchronous JavaScript and XML
- Skilgreint 2005
- Í dag ekki ein tækni heldur hugtakið að sækja gögn ósamstillt (async) til að koma í veg fyrir að hlaða allri síðunni aftur
- Same-origin policy segir til um að ekki megi hlaða gögnum frá annari síðu nema protocol, port og host sé það sama
- Megum þó vísa í og nota JavaScript, CSS, myndir o.fl.
- Þar sem same-origin policy bannar sjálfgefið að sækja gögn cross-origin þurfum við leið til að geta sótt gögn á milli þjóna
- CORS skilgreinir leið til að leyfa það
fetch
er nýlegt API til að eiga ajax samskipti- Mun þægilegra API sem notar promises
- Búum til request, einfaldasta leiðin er einfaldlega
fetch(url)
sem framkvæmirGET
áurl
og skilar Promise - Getum líka sent inn
options
hlut sem annað viðfang og gert þá t.d.POST
- Fáum til baka
response
hlut sem við athugumstatus
á eða hvortresponse.ok
sétrue
(ef status er 200–299)
- Eftir að við fáum response þurfum við að ákveða hvernig við fáum gögnin
JSON
meðresponse.json()
- Texta
response.text()
- Binary gögn
response.blob()
- Skilar allt Promise
- JavaScript hefur ekki eins villumeðhöndlun og HTML og CSS
- Ef eitthvað brotnar eru líkur á að það hafi áhrif á allt
- Verðum að hafa í huga
Alveg eins og við aðskiljum útlit frá efni viljum við aðskilja forrit frá efni.
Tengt progressive enhancement er hugtakið unobtrusive JavaScript.
- Aðskilnaður hegðunar frá markupi
- Sem minnst fótspor — ekki skilgreina í global scope
- Athuga hvort virkni sé studd og þá bæta henni við
- Ein leið til að vinna með flækjustig
- Blöndum saman einföldum föllum til að gera flókna hluti
- Búum til abstraction
- Gera a.m.k. annað af:
- Taka inn eitt eða fleiri fall sem argument
- Skila falli
- Önnur föll eru „á fyrstu stétt“
- Skila alltaf sama úttaki fyrir sama inntak
- Úttak veltur ekki á stöðu eða upplýsingum fyrir utan fall—óháð umhverfi sínu
- Fall veldur ekki breytingum á umhverfi – engar aukaverkanir
- Hugsum meira abstrakt – á hærra stigi
- Minni hávaði og meiri upplýsingar
- Getum gert fyrir helling af „venjulegum“ aðgerðum
- Höfum grunn föll til staðar í málinu
- Objects & encapsulation
- Ein af aðal hugmyndum hlutbundinnar forritunar er að skipta forritum upp og láta hvern hluta bera ábyrgð á eigin stöðu
- Hjúpum virkni og flækjustig, vinnum með í gegnum interface
this
hagar sér öðruvísi í JavaScript en í öðrum málum- Skilgreinist af því hvernig kallað er í fallið
- Utan hluta er
this
global hluturinn, þ.e. þar sem allt er geymt (í browserwindow
)
- Leyfir okkur að kalla í föll með ákveðnu
this
apply
– köllum í fall með gefnuthis
og fylki af argumentscall
– köllum í fall með gefnuthis
og lista af arguments
- Leyfir okkur að festa, binda,
this
fyrir föll - Kemur okkur ekki á óvart hvað
this
er - Getum líka bundið argument...
- Arrow föll eru öðruvísi—endurskilgreina ekki
this
this
er skilgreint eins og það var skilgreint í scope kringum fall
- Flestir hlutir hafa prótótýpu, hlutur sem geymir fleiri properties
- Ef við biðjum um property á hlut sem er ekki skilgreint á hlut er leitað á prótótýpu hans
- Hlutir fá eigindi frá prótótýpunni en eigindi á hlutnum hafa aldrei áhrif á keðjuna
- Getum ekki skrifað yfir hluti á prótótýpu
- Að setja eigindi á hlut setur það alltaf á honum sjálfum
- Í ECMAScript 6 er
class
skilgreint - Syntactic sugar til að herma eftir klassískum OO hlutum með prótótýpum
extends
,constructor
,super
,static
og getters og setters