javascript - NULL-sikker egenskapsaksesjon og betinget tildeling i EcmaScript 6+


Finnes det en operator som vil gjøre det mulig å uttrykke følgende logikk (på linje 4) mer konsist?

const query = succeed => (succeed? {value: 4} : undefined);

let value = 3;
for (let x of [true, false]) {
  try { value = query(x).value; } catch {} // <-- Don´t assign if no .value
}
console.log(value); 

Utdataene er 4. Hvis det ikke finnes noe .value-felt i responsen, vil jeg beholde den gamle value/ikke at tildelingen skal utføres.

Notater :
  • Hvis value=query(x)?.value ble brukt, ville det tildele undefined til value
  • Det finnes også operatoren ??=, men den er ikke nyttig her, value ??= ... vil bare tilordne hvis value for øyeblikket er null/undefined
  • I CoffeeScript, value=query(x).value if query(x)?.value? oppnår ønsket oppførsel uten try/catch, selv om det er repetitivt
  • value=query(x)?.value ?? value fungerer, men er ikke betinget tildeling, tildelingen skjer fortsatt. Hvis vi hadde satt en Objects egenskap, ville setter-metoden blitt kalt unødvendig. Det er også repetitivt
  • Denne logikken kan ikke abstrakteres til en funksjon, f.eks. value=smart(query(x), "value"), tildelingen kan ikke gjøres betinget på den måten
Nøkkelord?

null-propagasjon, eksistensoperator

Svar #1

I noen år nå har det rett og slett vært

a?.b?.c
a?.b?.c ?? "default"

Sjekk «Can I Use» for kompatibilitet: https://caniuse.com/mdn-javascript_operators_optional_chaining,mdn-javascript_operators_nullish_coalescing


Oppdatering (2022-01-13): Ser ut som folk fortsatt finner dette, her er den nåværende historien:

  • Valgfri kjeding er nå inkludert i spesifikasjonen (ES2020) og støttes av alle moderne nettlesere, mer i det arkiverte forslaget: https://github.com/tc39/proposal-optional-chaining
  • babel-preset-env: Hvis du trenger å støtte eldre miljøer som ikke har det, er dette sannsynligvis det du vil ha https://babeljs.io/docs/en/babel-preset-env
  • Babel v7-plugin: https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining

Oppdatering (2017-08-01): Hvis du vil bruke en offisiell plugin, kan du prøve alfa-versjonen av Babel 7 med den nye transformasjonen. Din erfaring kan variere

https://www.npmjs.com/package/babel-plugin-transform-optional-chaining

Original:

En funksjon som oppnår det er for øyeblikket i fase 1: Valgfri kjedning.

https://github.com/tc39/proposal-optional-chaining

Hvis du vil bruke det i dag, finnes det en Babel-plugin som gjør det.

https://github.com/davidyaha/ecmascript-optionals-proposal

Svar #2

Det er ikke like fint som ?. operatoren, men for å oppnå et lignende resultat kan du gjøre:

user && user.address && user.address.postcode

Siden null og undefined begge er falske verdier (se denne referansen), blir egenskapen etter &&-operatøren kun aksessert hvis den foregående ikke er null eller undefined.

Alternativt kunne du skrive en funksjon som dette:

function _try(func, fallbackValue) {
    try {
        var value = func();
        return (value === null || value === undefined) ? fallbackValue : value;
    } catch (e) {
        return fallbackValue;
    }
}

Bruk:

_try(() => user.address.postcode) // return postcode or undefined 

Eller, med en tilbakefallsverdi:

_try(() => user.address.postcode, "none") // return postcode or a custom string

Svar #3

2020-løsning, ?. og ??

Du kan nå direkte bruke ?. (Valgfri kjeding) inline for å trygt teste om noe eksisterer. Alle moderne nettlesere støtter det.

?? (Nullish Coalescing) kan brukes for å sette en standardverdi hvis den er undefined eller null.

aThing = possiblyNull ?? aThing
aThing = a?.b?.c ?? possiblyNullFallback ?? aThing

Hvis en eiendom eksisterer, går ?. videre til neste sjekk, eller returnerer den gyldige verdien. Enhver feil vil umiddelbart korteslutte og returnere undefined.

const example = {a: ["first", {b:3}, false]}

example?.a  // ["first", {b:3}, false]
example?.b  // undefined

example?.a?.[0]     // "first"
example?.a?.[1]?.a  // undefined
example?.a?.[1]?.b  // 3

domElement?.parentElement?.children?.[3]?.nextElementSibling

null?.()                // undefined
validFunction?.()       // result
(() => {return 1})?.()  // 1

For å sikre en forhåndsdefinert verdi, kan du bruke ??. Hvis du trenger den første sannhet-verdien, kan du bruke ||.

example?.c ?? "c"  // "c"
example?.c || "c"  // "c"

example?.a?.[2] ?? 2  // false
example?.a?.[2] || 2  // 2

Hvis du ikke sjekker en sak, må venstresidens egenskap eksistere. Hvis ikke, vil det kaste en unntak.

example?.First         // undefined
example?.First.Second  // Uncaught TypeError: Cannot read property 'Second' of undefined

?. Nettleserstøtte - 92 %, nov 2021

?? Nettleserstøtte - 92%

Mozilla-dokumentasjon

--

Logisk null-tilordning, 2020+ løsning

Nye operatorer blir for øyeblikket lagt til i nettleserne, ??=, ||= og &&=. De gjør ikke helt det du ser etter, men kan føre til samme resultat avhengig av hva målet med koden din er.

MERK: Disse er ikke vanlige i offentlige nettleserversjoner ennå, men Babel bør transpile godt. Vil oppdatere etter hvert som tilgjengeligheten endres.

??= sjekker om venstre side er udefinert eller null, og stopper hvis den allerede er definert. Hvis ikke, blir venstre side tildelt høyre side sin verdi. ||= og &&= er liknende, men basert på || og && operatorene.

Grunnleggende eksempler

let a          // undefined
let b = null
let c = false

a ??= true  // true
b ??= true  // true
c ??= true  // false

Objekt/Array-eksempler

let x = ["foo"]
let y = { foo: "fizz" }

x[0] ??= "bar"  // "foo"
x[1] ??= "bar"  // "bar"

y.foo ??= "buzz"  // "fizz"
y.bar ??= "buzz"  // "buzz"

x  // Array [ "foo", "bar" ]
y  // Object { foo: "fizz", bar: "buzz" }

Nettleserstøtte nov 2021 - 90%

Mozilla-dokumentasjon

Svar #4

Nei. Du kan bruke lodash#get eller noe sånt for dette i JavaScript.

Svar #5

Vaniljealternativ for sikker tilgang til egenskaper

(((a.b || {}).c || {}).d || {}).e

Den mest konsise betingede tildelingen ville sannsynligvis være denne

try { b = a.b.c.d.e } catch(e) {}

Relaterte artikler