javascript - NULL-säker åtkomst till egenskaper & villkorlig tilldelning i EcmaScript 6+
Finns det en operator som skulle tillåta att följande logik (på rad 4) uttrycks mer kortfattat?
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); Utdata är 4. Om det inte finns något .value-fält i svaret vill jag behålla det gamla value/vill inte att tilldelningen ska utföras.
Anteckningar:
- Om
value=query(x)?.valueanvändes, skulle det tilldelaundefinedtillvalue - Det finns också operatorn
??=, men den är inte användbar här,value ??= ...skulle bara tilldela omvalueför närvarande ärnull/undefined - I CoffeeScript uppnår
value=query(x).value if query(x)?.value?önskat beteende utantry/catch, även om det är repetitivt value=query(x)?.value ?? valuefungerar men är inte villkorsbaserad tilldelning, tilldelningen sker fortfarande, om vi skulle sätta enObjects egenskap skulle settern anropas i onödan. Det är också repetitivt- Denna logik kan inte abstraheras till en funktion, t.ex.
value=smart(query(x), "value"), tilldelningen kan inte göras villkorligt på det sättet
Nyckelord?
nullspridning, existensoperator
Svar #1
Under några år nu är det helt enkelt
a?.b?.c
a?.b?.c ?? "default"
Kolla "Can I Use" för kompatibilitet: https://caniuse.com/mdn-javascript_operators_optional_chaining,mdn-javascript_operators_nullish_coalescing
Uppdatering (2022-01-13): Det verkar som att folk fortfarande hittar detta, här är den aktuella historien:
- Valfri kedjning finns nu i specifikationen (ES2020) och stöds av alla moderna webbläsare, mer i det arkiverade förslaget: https://github.com/tc39/proposal-optional-chaining
- babel-preset-env: Om du behöver stödja äldre miljöer som inte har det, är detta förmodligen vad du vill ha https://babeljs.io/docs/en/babel-preset-env
- Babel v7-plugin: https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining
Uppdatering (2017-08-01): Om du vill använda ett officiellt plugin kan du prova alfa-versionen av Babel 7 med den nya transformen. Dina erfarenheter kan variera
https://www.npmjs.com/package/babel-plugin-transform-optional-chaining
Original:
En funktion som uppnår det är för närvarande i steg 1: Valfri kedjning.
https://github.com/tc39/proposal-optional-chaining
Om du vill använda det idag finns det ett Babel-plugin som uppnår det.
https://github.com/davidyaha/ecmascript-optionals-proposal
Svar #2
Det är inte lika trevligt som ?. operatorn, men för att uppnå ett liknande resultat kan du göra:
user && user.address && user.address.postcode
Eftersom null och undefined båda är falska värden (se denna referens), nås egenskapen efter &&-operatorn endast om föregångaren inte är null eller undefined.
Alternativt skulle du kunna skriva en funktion på det här sättet:
function _try(func, fallbackValue) {
try {
var value = func();
return (value === null || value === undefined) ? fallbackValue : value;
} catch (e) {
return fallbackValue;
}
}
Användning :
_try(() => user.address.postcode) // return postcode or undefined
Eller, med ett reservvärde:
_try(() => user.address.postcode, "none") // return postcode or a custom string
Svar #3
2020-lösning, ?. och ??
Du kan nu direkt använda ?. (Valfri kedjning) inline för att säkert testa om något finns. Alla moderna webbläsare stöder det.
?? (Nullish Coalescing) kan användas för att sätta ett standardvärde om värdet är undefined eller null.
aThing = possiblyNull ?? aThing
aThing = a?.b?.c ?? possiblyNullFallback ?? aThing
Om en egenskap finns, fortsätter ?. till nästa kontroll, eller returnerar det giltiga värdet. Ett fel kommer omedelbart att avbryta och returnera 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
För att säkerställa ett standardvärde som är definierat kan du använda ??. Om du behöver det första sanningsenliga värdet kan du använda ||.
example?.c ?? "c" // "c"
example?.c || "c" // "c"
example?.a?.[2] ?? 2 // false
example?.a?.[2] || 2 // 2
Om du inte kontrollerar ett fall måste egenskapen på vänster sida finnas. Om inte kommer det att kasta ett undantag.
example?.First // undefined
example?.First.Second // Uncaught TypeError: Cannot read property 'Second' of undefined
?. Webbläsarstöd - 92%, nov 2021
?? Webbläsarstöd - 92%
Mozilla-dokumentation
--
Logisk nullish-tilldelning, lösning från 2020+
Nya operatorer läggs för närvarande till i webbläsarna, ??=, ||= och &&=. De gör inte riktigt det du letar efter, men kan leda till samma resultat beroende på syftet med din kod.
NOTERA: Dessa är ännu inte vanliga i offentliga webbläsarversioner, men Babel bör transpileras väl. Kommer att uppdatera när tillgängligheten förändras.
??= kontrollerar om vänster sida är odefinierad eller null, och avbryter kortslutningen om den redan är definierad. Om inte, tilldelas vänster sida värdet från höger sida. ||= och &&= är liknande, men baserade på || och && operatorerna.
Grundläggande exempel
let a // undefined
let b = null
let c = false
a ??= true // true
b ??= true // true
c ??= true // false
Objekt/Array-exempel
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" }
Webbläsarstöd nov 2021 - 90%
Mozilla-dokumentation
Svar #4
Nej. Du kan använda lodash#get eller något liknande för detta i JavaScript.
Svar #5
Vaniljalternativ för säker åtkomst av egenskap
(((a.b || {}).c || {}).d || {}).e
Den mest kortfattade villkorsbaserade tilldelningen skulle förmodligen vara denna
try { b = a.b.c.d.e } catch(e) {}
