9 JavaScript-nyheter i ES2019

Flatmapping, strengtrimming, array-konvertering, valgfri fanging av feil og mye mer!

📷: SpaceX for Unsplash
📷: SpaceX for Unsplash Vis mer

JavaScript ble opprinnelig skrevet på ti (!) dager av Brendan Eich i 1995. Siden den gang har språket utviklet seg i flere omganger med rikere syntaks, standardbiblioteker og konvensjoner.

I spissen av utviklingen finner vi TC39-kommiteen til ECMA International — disse spesifiserer hvordan JavaScript burde tolkes, både i Node.js og de ulike nettleserene.

Denne standarden er altså ECMAScript. Formålet til ECMAScript er å formulere spesifikasjonene til språket slik at vi som utviklere har en offisiell syntaks å forholde oss til. Nå lanseres en ny slik standard hvert år.

La oss se på hva vi kan forvente oss i 2019!

String.prototype.trimStart og String.prototype.trimEnd

String.prototype.trim er nok kjent for de aller fleste, og har vært standardisert i Javascript siden ES5. Det er funksjonen man bruker for å fjerne whitespace fra begynnelsen og slutten av en streng.

trimStart() og trimEnd() er en oppsplitting av trim() som lar oss bestemme i hvilken ende av strengen vi ønsker å “trimme”.

const string = “ ES2019! Yay! “;
string.trimStart(); 
// “ES2019! Yay! ”
string.trimEnd();   
// “ ES2019! Yay!”

Object.fromEntries()

Object.fromEntries() konvertere en liste med nøkkel-verdi-par til et JavaScript-objekt. Funksjonen kan også sees på som motsetningen, eller reverseringen om du vil, til den eksisterende Object.entries()som kom i ES8(2017).

const entries = [ [‘foo’, ‘bar’] ];
const object = Object.fromEntries(entries);
// { foo: ‘bar’ }

Array.prototype.flat og Array.prototype.flatMap

flat() finner vi på prototypen til Array. Den lar oss flate ut nøstede lister ned til en dybde angitt av heltallet funksjonen tar inn som parameter. Parameteret kan også utelates og da kjøres funksjonen med en standardverdi på 1, tilsvarende å kalle flat(1).

[ 1, 2, [ 3, 4 ] ].flat(); 
// [ 1, 2, 3, 4 ] 
[ 1, 2, [ 3, 4, [ 5, 6 ] ] ].flat(2);
// [ 1, 2, 3, 4, 5, 6 ] 

flatMap er også en ny funksjon på prototypen til Array. flatMap er i praksis en kombinasjon av Array.prototype.map og Array.prototype.flat. Det vil si at den først kjører en mapping-funksjon over listen, for deretter forsøke å flate ut resultatet.

I motsetning tilflat(), hvor det er anledning til å angi et parameter for hvor dypt i nøstingen listene skal flates ut, vil flatMap() kun benytte flat() under panseret. Dette tilsvarer flat(1), altså et nivå dypt.

[ [1], [2], [3], [4] ].flatMap(x => x[0] + 1 );
// [ 2, 3, 4, 5]

Historien om hvordan funksjonen endte opp med navnet flat er en morsom historie. Det første forslaget var nemlig flatten, men dette ble fort skrinlagt da det førte til en kollisjon med biblioteket MooTools. I kjølvannet av dette var det noen som foreslo navnet smoosh på spøk.

Symbol#description

Symbols er ikke noe man ser så ofte. Det er en primitiv variabel-type som ble introdusert i ES6 som du kan lese mer om her hvis du er over snittet interessert i JavaScript.

Ved instansieringen av Symbol er det mulig å spesifisere en beskrivelse med ett streng parameter.

const symbol = Symbol(‘Beskrivelse’)

Tidligere var det kun mulig å hente ut denne beskrivelsen ved å konvertere symbolet til en streng.

symbol.toString()
// ‘Symbol(Beskrivelse)’

De nye ES2019 endringene gjør det nå mulig å hente beskrivelsen direkte.

ECMAScript superset av JSON

Tidligere kunne ikke ECMAScript-strenger inneholde bokstavene U+2028 (linjeseperatør) og U+2029 (avsnittseperatør). Disse ble håndtert som linjeterminatorer og resulterte derfor i syntaksfeil (SyntaxError).

eval(‘“\u2028”’);
// SyntaxError

Mens JSON-strenger kan inneholde både U+2028 og U+2029 uten at det produserer feil.

JSON.parse(‘“\u2028”’);
// ''

I ES2019 er det besluttet å fjerne denne begrensningen. Noe som vil forenkle spesifikasjonen, da man ikke lenger trenger separate regler for strenger og JSON-strenger.

Valgfri catch binding

Tidligere var det obligatorisk med ett parameter i catch-blokken, uavhengig om den ble brukt eller ikke:

const erGyldigJSON = (tekst) => {
  try {
    JSON.parse(tekst)
    return true;
  } catch(error) { // Ubrukt error-parameter
    return false;
  }
}

Som vi ser ovenfor finnes det tilfeller der error-parameteret er overflødig. De nye ES2019 endringene gjør at vi kan utelate parameteret

const erGyldigJSON = (tekst) => {
  try {
    JSON.parse(tekst);
    return true;
  } catch { // Uten error-parameter
    return false;
  }
}

Well-formed JSON.stringify

Hvis du liker å bruke emojis i koden din har du kanskje stusset over følgende:

"😎".length
// 2

Grunnen til at JavaScript tolker smilefjeset som to tegn er fordi UTF-16 representerer emojis (og andre, uvanlige tegn) som en kombinasjon av to surrogater. Smilefjeset vårt kodes med tegnene '\uD83D' og '\uDE0E'. Hvis man derimot prøver å skrive et slikt tegn alene, for eksempel '\uD83D', regnes dette som en ugyldig tekststreng.

Nyheten i ES2019 ligger i hvordan JSON.stringify() håndterer slike ensomme surrogater. I tidligere versjoner ville disse bli erstattet med et spesialtegn:

JSON.stringify('\uD83D');
// '"�"'

Nå vil funksjonen heller sette inn en “escape character” før tegnkoden slik at resultatet fremdeles er lesbart og gyldig UTF-8/UTF-16-kode:

JSON.stringify('\uD83D');
// '"\\ud83d"'

Merk at JSON.parse(stringified) fungerer akkurat som før!

Stable Array#sort

Med ES2019 garanteres vi stabil listesortering! Før har spesifikasjonene tillatt ustabile sorteringsalgoritmer som QuickSort. Nå bruker alle de store nettleserene stabile sorteringsalgoritmer, og ECMAScript har utviklet seg sådan. I praksis betyr det at hvis vi har en Array av objekter og sorterer dem på en gitt nøkkel, vil elementene i listen beholde posisjonen sin relativt til de andre objektene med samme nøkkel.

Test selv om nettleseren din bruker en stabil sorteringsalgoritme!

Revised Function#toString

Fra og med ES2019 må Function.prototype.toString() returnere faktiske tekstsnutter fra kildekoden, fra indeksen funksjonen starter til den slutter. Dette innebærer at også kommentarer, mellomrom og syntaksdetaljer returneres i samme slengen.

Si vi har en funksjon foo:

function /* en kommentar! */ foo () {}

Tidligere ville Function.prototype.toString() returnert en tekstvariant av funksjonen uten kommentarer og mellomrom:

foo.toString();
// 'function foo() {}'

Men nå hentes altså funksjonen akkurat slik utvikleren har uttrykket seg!

foo.toString();
// 'function /* en kommentar! */ foo () {}'

Phew!