Nyheter i JavaScript - ES2021

I juni 2021 kom det en håndfull med nye features i JavaScript språket.

Gaute Meek Olsen

TLDR - Too Long, Didn't Read

Hvis du ikke ønsker å lese hele artikkelen, så har jeg samlet de viktigste endringene i dette bildet.

Bakgrunn

Hvert år i juni så kommer det en ny utgave av ECMAScript som er spesifikasjonen av JavaScript. Dette tilfører nye features som kan brukes og gjør JavaScript bedre. I år ble ES2021, også kjent som ES12, sluppet, og jeg skal gå gjennom hva som er nytt.

Numeric separators

Hvis koden din inneholder tall med mange siffer, kan den fort bli vanskelige å lese. Altså at man må telle nuller for å finne ut om det er en million eller ti millioner, for eksempel. Nå er det tillatt å benytte underscore i tallet for å synliggjøre f.eks. tusen-deler.

const hardToRead = 1000000000;
const easyToRead = 1_000_000_000;
console.log(hardToRead === easyToRead); // Output: true
const decimal = 1.333_333;

replaceAll

Når man jobber med strings i JavaScript kommer det av og til behov for å bytte ut deler av teksten med noe annet. Tidligere har man kunnet benytte `replace` metoden, men denne bytter kun ut første forekomst. Dette har vi kunnet løst med regex med et globalt flagg. Nå har vi en ny metode kalt `replaceAll` slik at vi slipper å benytte regex hvis vi ikke vil.

const apples = '🍏🍏🍏';
const oranges = apples.replaceAll('🍏', '🍊');
console.log(oranges) // Output: 🍊🍊🍊

Promise.any

Hvis vi har flere asynkrone kall som kjører i parallell og vi ønsker å fortsette så fort et av dem er fullført, så har vi kunnet samlet disse med `Promise.race`. Men denne vil fullføres uavhengig om det raskeste kallet feiler eller er suksessfullt. Hvis vi ønsker å vente til det første suksessfulle kallet er ferdig, kan vi nå benytte `Promise.any`.

try{
const promises = [fetch('/slow'), fetch('/fast')];
const first = await Promise.any(promises);
} catch(error) {
console.error('Every promise failed', error.errors);
}

Logical assignment

Du kjenner kanskje til de logiske operatorene `&&`, `||` og `??`. Nå kan vi benytte disse til å assigne en variabel.

x &&= y;
// x is unchanged if it's falsy, otherwise y
x ||= y;
// x is unchanged if it's truthy, otherwise y
x ??= y;
// x is unchanged if it's null or undefined, otherwise y

Dette kan virke ganske likt og det samme som dette:

x = x && y;

Men dette følger sine logiske operatorers short-circuiting, som vil si at de assigner kun til variabelen hvis den logiske operatoren vil evaluere den høyre side. Så det er egentlig det samme som:

x && (x = y);

Dette kan av og til ha noe å si siden en assignment kan føre til en side effect. Dette er demonstrert i denne kodesnutten:

const obj = {
value: 0,
get y() {
return this.value;
},
set y(value){
console.log('side-effect');
this.value = value;
}
}
obj.y ??= 99; // no side-effect
obj.y = obj.y ?? 99; // Output: side-effect

WeakRef

JavaScript benytter seg av garbage collect til å frigjøre minnet. Men så lenge noen har en referanse til objektet, så kan det ikke bli garbage collected og må bli holdt i minnet. Nå kan vi benytte `WeakRef` hvis vi synes det er greit at garbage collector kan frigjøre objektet fra minnet hvis det trengs uten at vi har kontroll over det. Hvis det er blitt tømt fra minnet vil `deref()` returnere `undefined`. Trengs det kontroll over når det blir tømt, kan vi benytte `FinalizationRegistry` for å registrere en callback hvis objektet blir tatt av garbage collector.

const cacheRef = new WeakRef({ count: 0 });
const cache = cacheRef.deref();
if(cache){
console.log(cache.count);
} else {
console.log('cache object lost to garbage-collection');
}
// FinalizationRegistry let's you assign a callback if object is garbage-collected
const registry = new FinalizationRegistry((value) => {
console.log(value);
});
registry.register(cacheRef.deref(), 'cacheRef is lost');

Merk at dette er kode du ønsker å unngå hvis mulig, da bruk av `WeakRef` bør nøye tenkes ut. For når garbage collector vil bli kjørt, har vi liten innsikt i og kan variere mellom ulike nettlesere.