# JavaScript

## Hvad det er

JavaScript er et dynamisk typet programmeringssprog, standardiseret under navnet ECMAScript, som
enhver webbrowser kan afvikle, og som også kører på servere og byggemaskiner gennem
afviklingsmiljøer som Node.js. I daglig tale hedder det JS. Standardens årlige udgaver hedder
ES2015, ES2024 og så videre, de gamle numre (ES5, ES6) høres stadig, og »vanilla JavaScript« betyder
sproget uden et framework ovenpå. Bortset fra navnet og de krøllede parenteser har det meget lidt
med Java at gøre.

Brendan Eich skrev den første version hos Netscape, og den kom med i browseren Navigator 2.0. Ecma
International vedtog første udgave af standarden, ECMA-262, i juni 1997, og organisationens komité
TC39 har udsendt en ny udgave hvert år siden ECMAScript 2016. Et forslag kommer først med i
specifikationen på trin 4 i komitéens proces, og det trin kræver implementeringer, der allerede er
sendt ud. Derfor er teksten og motorerne sjældent uenige ret længe.

Sproget selv siger meget lidt om verden udenfor. ECMA-262 definerer syntaksen, typerne, objekter,
promises og moduler og overlader input og output til det miljø, der afvikler sproget, og som
standarden kalder værten. I en browser er værten webplatformen: dokumentet, hændelser, timere og
netværkskald, som for det meste er beskrevet i HTML Standard og dens søsterstandarder. I Node.js
stiller værten i stedet filer, sockets og processer til rådighed. Den deling forklarer en klassisk
overraskelse: kode kan være fuldt gyldig JavaScript og alligevel gå i stykker, når den flytter fra
en side til en server, for sproget flyttede med, mens værten blev hjemme.

I browseren deler en sides scripts én hovedtråd med layout, tegning og input. En opgave kører
færdig, før browseren kan reagere på det næste klik. Promises og `async`-funktioner holder
ventetiden væk fra tråden, men beregninger bliver på den, medmindre de flyttes over i en Web Worker.
Tal er IEEE 754-værdier med dobbelt præcision, så hele tal er kun eksakte op til 2^53 − 1, og alt
derover kræver `BigInt`.

## Hvorfor det betyder noget

Den egentlige beslutning handler om, hvor meget af det man sender til dem, der læser sitet.
JavaScript er det sprog, der får en side til at reagere uden en tur forbi serveren, og hver kilobyte
af det skal hentes, parses, kompileres og afvikles på en enhed, man ikke selv råder over. Et bundt,
der føles øjeblikkeligt på en udviklers bærbare, kan holde en mellemklassetelefon beskæftiget i
flere sekunder, og regningen betaler læseren med batteri og tålmodighed.

Script er også der, hvor en side står mest åben. Alt, hvad der bliver sprøjtet ind i den, kører med
sidens fulde rettigheder: det kan læse, hvad læseren taster, og sende det hvor som helst, siden selv
må sende hen. Det er den risiko, Content Security Policy findes for at inddæmme, og en side helt
uden script giver angriberen intet at arbejde med. Pakkeøkosystemet åbner en anden flanke. Et typisk
frontendbyg trækker hundredvis af transitive afhængigheder med sig, og hver eneste af dem er kode,
der kører med de samme rettigheder som ens egen.

Den anden side af regnestykket er lige så virkelig. Når det samme sprog kører på begge sider af et
system, kan browseren og serveren dele en valideringsregel eller en dataform, og nogle produkter har
brug for meget script: offlinetilstand, træk og slip, kort, samarbejde i realtid. Det nyttige
spørgsmål stilles derfor funktion for funktion: skal det her ske i læserens browser, uden at en
server bliver spurgt? Lyder svaret nej, så lad serveren eller bygningen lave HTML'en, og send den.

Det beslægtede valg står mellem JavaScript og TypeScript. TypeScript tilføjer en typetjekker og et
byggetrin og kompilerer tilbage til almindelig JavaScript. I en kodebase, som flere mennesker ændrer
hver uge, tjener tjekkeren som regel sig selv hjem. Til en forbedring på hundrede linjer på en
statisk side rækker JavaScript og en streng linter.

## Sådan ser det ud i praksis

Dette site sender næsten ingen JavaScript til sine læsere og afvikler en hel del af det, når det
bygges. Tre sider viser begge halvdele.

Det offentlige site er et statisk byg på tre sprog uden en backend, der kører, og browseren modtager
ét eneste førstepartsscript.
[Scriptet er en afgrænset undtagelse](/da/portfolio/built-a-multilingual-static-site-in-hugo-126/)
til én funktion, et porteføljefilter, hvis kontroller er skjult, indtil scriptet har kørt. Resten af
sitet, 108 skabelonfiler med 53 partials og 18 shortcodes, gør sit arbejde, mens sitet bygges. Siden
skriver også prisen for det valg ned: alt interaktivt skal løses ved bygningstid, og derfor blev et
søgeindeks prissat og parkeret i stedet for at blive sendt ud.

Det samme indhold udgives over Gemini og Gopher, to protokoller, hvor et script slet ikke har nogen
plads.
[Bygget frembringer 777 Gemini-dokumenter og 777 Gopher-menuer](/da/portfolio/mirrored-the-site-to-gemini-and-gopher-137/)
fra den samme kilde, og en måling bekræftede, at HTML'en forblev uændret ned til sidste byte. De to
alternativer lægger omkring tolv procent oven i HTML'ens vægt på disken. Sitets argument er, at et
dokument klarer sig uden en megabyte script for at blive læst, og et format, der slet ikke kan rumme
et script, er den mest ligefremme måde at vise det på.

Det meste JavaScript her bor i værktøjerne. Sitets kvalitetsgate er toogtredive scripts og 10.242
linjer JavaScript, den største kodemængde i repositoryet, og i en periode var det den eneste kode,
som hverken blev formateret, lintet eller typetjekket.
[Arbejdet med at få den under en formatter og en linter](/da/portfolio/brought-the-quality-gate-code-under-a-linter-143/)
begyndte med at tilpasse formatteren til koden: repositoryets standard på fire mellemrum ville have
omskrevet 2.173 linjer af den største tjekker, og en overstyring til to mellemrum for de filer
efterlod 38 linjers ægte drift. Derefter rejste linteren 13 fund, og alle 13 blev rettet uden en
eneste undertrykkelse. En fejl i en tjekker viser sig som et tjek, der består, når det burde slå
fejl, og derfor får gatens egen kode den behandling, den selv giver alt andet.

## Hvor det går galt

Fejlene herunder følger af, hvordan sproget er skruet sammen, og hver af dem har en kendt løsning.

**Siden er tegnet, men reagerer først på tryk et sekund senere.** En lang opgave, som at hydrere et
stort bundt, parse et stort JSON-svar eller sortere tusindvis af rækker, optager den ene tråd, der
håndterer input. Send mindre kode til den første interaktion ved at dele bundtet op pr. rute og
udskyde resten, del langt arbejde op i bidder, der giver kontrollen tilbage til event-loopet, og
flyt tunge beregninger over i en Web Worker. Mål på en langsom telefon frem for på den bærbare,
koden blev skrevet på.

**Priser og id'er kommer ud en anelse forkerte.** Hvert tal er et binært flydende kommatal, så
decimalbrøker afrundes, og meget store heltal falder sammen med deres naboer. En 64-bit
databasenøgle sendt som et JSON-tal er det typiske offer:

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

Hold beløb i hele mindsteenheder som øre, send store id'er som strenge, og brug `BigInt`, hvor
regnestykket skal være eksakt.

**En sammenligning lukker den forkerte værdi igennem.** Operatoren `==` konverterer sine operander,
før den sammenligner, så `"" == 0` og `"0" == false` er begge sande. Brug `===` overalt, og lad
linterens regel `eqeqeq` håndhæve det, så en konvertering kun sker, når koden udtrykkeligt beder om
den.

**Tekst fra en bruger ender med at køre som kode.** At tildele utroværdig tekst til `innerHTML`, at
bygge markup ved at sætte strenge sammen eller at give input videre til `eval` gør data til script.
Skriv tekst med `textContent`, send en Content Security Policy, der kun lukker scripts ind via nonce
eller hash, og hold listen over afhængigheder kort og fastlåst i en lockfile, så hver opdatering
bliver læst, før den kommer ind.

**Kode, der virker i browseren, går ned på serveren.** Sproget flyttede, værten blev: `window` og
`document` findes kun i en browser, og Node.js læser en fil som CommonJS eller som ES-modul
afhængigt af indstillinger, browseren aldrig ser. Hold værtsspecifikke kald ude i kanterne, sæt
`"type": "module"` eksplicit i `package.json`, og kør hver del af koden i det miljø, den faktisk
skal køre i.

## Læs mere

- [ECMAScript Language Specification](https://tc39.es/ecma262/) — det levende udkast til ECMA-262,
  den tekst alle motorer implementerer, opdateret efterhånden som forslag når trin 4.
- [The TC39 Process](https://tc39.es/process-document/) — de trin, et forslag går igennem, før det
  bliver en del af sproget, og hvad hvert trin kræver.
- [ECMA-262 hos Ecma International](https://ecma-international.org/publications-and-standards/standards/ecma-262/)
  — de udgivne årlige udgaver, til når et projekt skal navngive den version, det sigter efter.
- [HTML Standard: event loops](https://html.spec.whatwg.org/multipage/webappapis.html#event-loops) —
  hvordan en browser planlægger opgaver, mikroopgaver og rendering omkring en sides scripts.
- [HTML Standard: the script element](https://html.spec.whatwg.org/multipage/scripting.html#the-script-element)
  — klassiske scripts og modulscripts, og hvordan `async` og `defer` ændrer, hvornår de kører.

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