Null-safe property access (and conditional assignment) in ES6/2015

后端 未结 10 1066
[愿得一人]
[愿得一人] 2020-11-22 13:00

Is there a null-safe property access (null propagation / existence) operator in ES6 (ES2015/JavaScript.next/Harmony) like ?. in

相关标签:
10条回答
  • 2020-11-22 13:35

    Going by the list here, there is currently no proposal to add safe traversal to Ecmascript. So not only is there no nice way to do this, but it is not going to be added in the forseeable future.

    0 讨论(0)
  • 2020-11-22 13:36

    2020 Solution, ?. and ??

    You can now directly use ?. (Optional Chaining) inline to safely test for existence. All modern browsers support it.

    ?? (Nullish Coalescing) can be used to set a default value if undefined or null.

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

    If a property exists, ?. proceeds to the next check, or returns the valid value. Any failure will immediately short-circuit and return 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
    

    To ensure a default defined value, you can use ??. If you require the first truthy value, you can use ||.

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

    If you do not check a case, the left-side property must exist. If not, it will throw an exception.

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

    ?. Browser Support - 82%, Oct 2020

    ?? Browser Support - 82%

    Mozilla Documentation

    --

    Logical nullish assignment, 2020+ solution

    New operators are currently being added to the browsers, ??=, ||= and &&=. They don't do quite what you are looking for, but could lead to same result depending on the aim of your code.

    NOTE: These are not common in public browser versions yet, but Babel should transpile well. Will update as availability changes.

    ??= checks if left side is undefined or null, short-circuiting if already defined. If not, the left side is assigned the right-side value. ||= and &&= are similar, but based on the || and && operators.

    Basic Examples

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

    Object/Array Examples

    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" }
    

    Browser Support Oct 2020 - 70%

    Mozilla Documentation

    0 讨论(0)
  • 2020-11-22 13:42

    Vanilla alternative for safe property access

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

    The most concise conditional assignment would probably be this

    try { b = a.b.c.d.e } catch(e) {}
    
    0 讨论(0)
  • 2020-11-22 13:42

    A safe deep get method seems like a natural fit for underscore.js but there the issue is avoiding string programming. Modifying @Felipe's answer to avoid string programming (or at least pushes edge cases back to the caller):

    function safeGet(obj, props) {
       return (props.length==1) ? obj[keys[0]] :safeGet(obj[props[0]], props.slice(1))
    }
    

    Example:

    var test = { 
      a: { 
        b: 'b property value',
        c: { }
      } 
    }
    safeGet(test, ['a', 'b']) 
    safeGet(test, "a.b".split('.'))  
    
    0 讨论(0)
  • 2020-11-22 13:43

    No. You may use lodash#get or something like that for this in JavaScript.

    0 讨论(0)
  • 2020-11-22 13:43
    // Typescript
    static nullsafe<T, R>(instance: T, func: (T) => R): R {
        return func(instance)
    }
    
    // Javascript
    function nullsafe(instance, func) {
        return func(instance);
    };
    
    // use like this
    const instance = getSomething();
    let thing = nullsafe(instance, t => t.thing0.thing1.thingx);
    
    0 讨论(0)
提交回复
热议问题