# JavaScript

## Hva det er

JavaScript er et dynamisk typet programmeringsspråk, standardisert som ECMAScript, som enhver
nettleser kan kjøre, og som også kjører på servere og byggemaskiner gjennom kjøremiljøer som
Node.js. Mange forkorter det til JS. Standardens årlige utgaver heter ES2015, ES2024 og så videre,
den eldre nummereringen (ES5, ES6) høres fortsatt, og «vanilla JavaScript» betyr språket uten noe
rammeverk oppå. Bortsett fra navnet og en del syntaks med krøllparenteser har det lite til felles
med Java.

Brendan Eich skrev den første versjonen hos Netscape, og den ble levert med nettleseren Navigator
2.0. Ecma International vedtok den første utgaven av standarden, ECMA-262, i juni 1997, og komiteen
TC39 har publisert en ny utgave hvert år siden ECMAScript 2016. Et forslag kommer inn i
spesifikasjonen først på trinn 4 i komiteens prosess, og det trinnet krever implementasjoner som
allerede er levert, så teksten og motorene er sjelden uenige lenge.

Språket sier svært lite om verden utenfor. ECMA-262 definerer syntaksen, typene, objekter, promises
og moduler, og overlater inndata og utdata til det miljøet som er vert for språket. I en nettleser
er den verten webplattformen: dokumentet, hendelser, tidtakere og nettverksforespørsler, spesifisert
for det meste i HTML-standarden og søsterstandardene dens. I Node.js leverer verten i stedet filer,
sockets og prosesser. Det skillet forklarer en vanlig overraskelse: kode kan være helt gyldig
JavaScript og likevel slutte å virke når den flyttes fra en side til en server, fordi språket ble
med og verten ble igjen.

I en nettleser deler skriptene på en side én hovedtråd med layout, tegning og inndata. En oppgave
kjører ferdig før nettleseren kan svare på neste klikk. Promises og `async`-funksjoner holder
ventingen utenfor den tråden, mens beregninger blir værende på den med mindre de flyttes til en Web
Worker. Tall er flyttall med dobbel presisjon etter IEEE 754, så heltall er eksakte bare opp til
2^53 − 1, og alt større krever `BigInt`.

## Hvorfor det er viktig

Den egentlige avgjørelsen er hvor mye av det du skal sende til dem som leser nettstedet ditt.
JavaScript er språket som får en side til å oppføre seg uten en rundtur til en server, og hver
kilobyte av det lastes ned, parses, kompileres og kjøres på en enhet du ikke har kontroll over.
Pakken som føles øyeblikkelig på en utviklers bærbare maskin, kan holde en mellomklassetelefon
opptatt i flere sekunder, og leseren betaler for det med batteri og tålmodighet.

Skript er også der en side er mest utsatt. Alt som injiseres i det, kjører med sidens fulle
myndighet: det kan lese det leseren skriver, og sende det hvor som helst siden har lov til å sende
noe. Det er den risikoen Content Security Policy finnes for å begrense, og en side uten skript har
ingenting å injisere i. Pakkeøkosystemet legger til en eksponering til. Et typisk bygg av en
frontend trekker inn hundrevis av transitive avhengigheter, og hver av dem er kode som kjører med de
samme rettighetene som din egen.

Den andre siden av regnskapet er reell. Ett språk på begge sider av et system lar nettleseren og
serveren dele en valideringsregel eller en dataform, og noen produkter trenger mye skript: tilstand
uten nett, dra og slipp, kart, samarbeid i sanntid. Det nyttige spørsmålet stilles per funksjon: må
dette skje i leserens nettleser uten å spørre en server? Hvis ikke, gjengi det på serveren eller ved
byggetid og send HTML.

Det beslektede valget er JavaScript mot TypeScript. TypeScript legger til en typekontroll og et
byggesteg, og kompileres tilbake til ren JavaScript. For en kodebase som flere personer endrer hver
uke, betaler typekontrollen som regel for seg selv; for en forbedring på hundre linjer på en statisk
side holder det med JavaScript og en streng linter.

## Slik ser det ut i praksis

Dette nettstedet sender nesten ingen JavaScript til leserne sine og kjører svært mye av det ved
byggetid. Tre sider viser begge halvdelene av det.

Det offentlige nettstedet er et statisk bygg på tre språk uten noen backend ved kjøretid, og
nettleseren mottar ett eneste førstepartsskript.
[Det skriptet er et avgrenset unntak](/nb/portfolio/built-a-multilingual-static-site-in-hugo-126/)
for én funksjon, et porteføljefilter der kontrollene holdes skjult til skriptet har kjørt. Resten av
nettstedet, 108 malfiler med 53 partials og 18 shortcodes, gjør jobben sin når nettstedet bygges.
Siden skriver også ned prisen for det valget: alt interaktivt må løses ved byggetid, og det er
grunnen til at en søkeindeks ble kostnadsberegnet og lagt på is i stedet for levert.

Det samme innholdet publiseres over Gemini og Gopher, to protokoller uten plass til skript i det
hele tatt.
[Bygget produserer 777 Gemini-dokumenter og 777 Gopher-menyer](/nb/portfolio/mirrored-the-site-to-gemini-and-gopher-137/)
fra den samme kilden, og en måling bekreftet at HTML-en ikke endret seg med en eneste byte. De to
alternative formatene legger omtrent 12 % til vekten av HTML-en på disk. Nettstedet argumenterer for
at et dokument ikke trenger en megabyte skript for å kunne leses, og et format som ikke kan romme
skript, er den enkleste måten å vise det på.

Det meste av JavaScript-koden her ligger i verktøyene. Kvalitetsporten på nettstedet er trettito
skript og 10 242 linjer JavaScript, den største kodemengden i repoet, og en tid var den den eneste
kodemengden som ingenting formaterte, lintet eller typekontrollerte.
[Å få den under en formaterer og en linter](/nb/portfolio/brought-the-quality-gate-code-under-a-linter-143/)
begynte med å tilpasse formatereren til koden: repoets standard på fire mellomrom ville ha skrevet
om 2 173 linjer i det største kontrollskriptet, og en overstyring til to mellomrom for de filene
etterlot 38 linjer med reelle avvik. Linteren ga deretter 13 funn, og alle 13 ble rettet, ingen
undertrykt. En feil i et kontrollskript viser seg som en kontroll som består når den burde feile, så
portens egen kode får den samme behandlingen som den gir alt annet.

## Hvor det går galt

Feilene nedenfor følger av hvordan språket er bygd, og hver av dem har en kjent løsning.

**Siden tegnes, men ignorerer trykk i et sekund eller mer.** En lang oppgave, som å hydrere en stor
kodebunt, parse et stort JSON-svar eller sortere tusenvis av rader, holder den ene tråden som
håndterer inndata. Send mindre kode for den første interaksjonen ved å dele kodebuntene per rute og
utsette resten, del opp langt arbeid i biter som gir kontrollen tilbake til hendelsesløkken, og
flytt tunge beregninger til en Web Worker. Mål på en treg telefon og ikke på den bærbare maskinen
koden ble skrevet på.

**Priser og identifikatorer kommer ut litt feil.** Hvert tall er et binært flyttall, så
desimalbrøker rundes av, og svært store heltall kollapser inn i naboene sine. En 64-biters
databasenøkkel sendt som et JSON-tall er det vanlige offeret:

```js
0.1 + 0.2 === 0.3; // false
Number.MAX_SAFE_INTEGER; // 9007199254740991
9007199254740993 === 9007199254740992; // true
```

Hold pengebeløp i heltall av den minste enheten, som øre eller cent, send store identifikatorer som
strenger, og bruk `BigInt` der regnestykket må være eksakt.

**En sammenligning slipper gjennom feil verdi.** Operatoren `==` konverterer operandene før den
sammenligner dem, så `'' == 0` og `'0' == false` er begge sanne. Bruk `===` overalt og la regelen
`eqeqeq` i linteren håndheve det, slik at konverteringen blir noe koden ber uttrykkelig om.

**Tekst fra en bruker ender opp med å kjøre som kode.** Å tilordne ubetrodd tekst til `innerHTML`,
bygge markup ved å skjøte sammen strenger eller sende inndata til `eval` gjør data om til skript.
Skriv tekst med `textContent`, send en Content Security Policy som bare slipper inn skript med nonce
eller hash, og hold avhengighetslisten kort og låst i en låsefil, og les hva hver oppdatering
trekker inn.

**Kode som virker i nettleseren, krasjer på serveren.** Språket flyttet seg, men verten gjorde det
ikke: `window` og `document` finnes bare i en nettleser, og Node.js leser en fil som CommonJS eller
som en ES-modul avhengig av innstillinger nettleseren aldri ser. Hold vertsspesifikke kall i
kantene, sett feltet `type` til `module` eksplisitt i `package.json`, og kjør hver kodebit i det
miljøet den faktisk skal kjøre i.

## Les mer

- [ECMAScript Language Specification](https://tc39.es/ecma262/) — det levende utkastet til ECMA-262,
  teksten hver motor implementerer, oppdatert etter hvert som forslag når trinn 4.
- [The TC39 Process](https://tc39.es/process-document/) — trinnene et forslag går gjennom før det
  blir en del av språket, og hva hvert av dem krever.
- [ECMA-262 hos Ecma International](https://ecma-international.org/publications-and-standards/standards/ecma-262/)
  — de publiserte årlige utgavene, for når et prosjekt må navngi versjonen det sikter mot.
- [HTML Standard: event loops](https://html.spec.whatwg.org/multipage/webappapis.html#event-loops) —
  hvordan en nettleser planlegger oppgaver, mikrooppgaver og tegning rundt skriptene på en side.
- [HTML Standard: the script element](https://html.spec.whatwg.org/multipage/scripting.html#the-script-element)
  — klassiske skript og modulskript, og hvordan `async` og `defer` endrer når de kjører.

<https://engineer.company/nb/glossary/javascript/>
