安全地访问Javascript嵌套对象

Hub*_*ris 14 javascript node.js

我有基于json的数据结构,对象包含嵌套对象.为了访问特定的数据元素,我一直在链接对象属性的引用.例如:

var a = b.c.d;
Run Code Online (Sandbox Code Playgroud)

如果未定义b或bc,则会因错误而失败.但是,我希望得到一个值,如果它存在,否则只是未定义.在不检查链中的每个值是否存在的情况下,最好的方法是什么?

我想保持这种方法尽可能通用,所以我不必添加大量的辅助方法,如:

var a = b.getD();
Run Code Online (Sandbox Code Playgroud)

要么

var a = helpers.getDFromB(b);
Run Code Online (Sandbox Code Playgroud)

我也想尝试避免try/catch构造,因为这不是一个错误所以使用try/catch似乎是错误的.这合理吗?

有任何想法吗?

Abd*_*dul 28

ECMAScript2020和 Node v14 中具有可选的链接运算符(我见过它也称为安全导航运算符),这将允许您的示例编写为:

var a = b?.c?.d;

来自MDN 文档

可选的链接运算符 (?.) 允许读取位于连接对象链深处的属性值,而无需明确验证链中的每个引用是否有效。这 ?。运算符的功能与 . 链接运算符,不同之处在于,如果引用为空(空或未定义),则表达式会短路并返回未定义的值,而不是导致错误。当与函数调用一起使用时,如果给定函数不存在,则返回 undefined。


esp*_*esp 11

标准方法:

var a = b && b.c && b.c.d && b.c.d.e;
Run Code Online (Sandbox Code Playgroud)

很快但不太优雅(尤其是更长的属性名称).

使用函数遍历JavaScipt对象属性既不高效也不优雅.

试试这个:

try { var a = b.c.d.e; } catch(e){}
Run Code Online (Sandbox Code Playgroud)

如果您确定a以前没有使用或

try { var a = b.c.d.e; } catch(e){ a = undefined; }
Run Code Online (Sandbox Code Playgroud)

如果您之前已经分配过它.

这可能比第一个选项更快.


Dan*_*oni 9

ES6 有可选链,可以按如下方式使用:

const object = { foo: {bar: 'baz'} };

// not found, undefined
console.log(object?.foo?.['nested']?.missing?.prop)

// not found, object as default value
console.log(object?.foo?.['nested']?.missing?.prop || {})

// found, "baz"
console.log(object?.foo?.bar)
Run Code Online (Sandbox Code Playgroud)

这种方法需要定义变量“object”并且它是一个对象。

或者,您可以定义自己的实用程序,这是一个实现递归的示例:

const traverseObject = (object, propertyName, defaultValue) => {
  if (Array.isArray(propertyName)) {
    return propertyName.reduce((o, p) => traverseObject(o, p, defaultValue), object);
  }

  const objectSafe = object || {};

  return objectSafe[propertyName] || defaultValue;
};

// not found, undefined
console.log(traverseObject({}, 'foo'));

// not found, object as default value
console.log(traverseObject(null, ['foo', 'bar'], {}));

// found "baz"
console.log(traverseObject({foo: {bar:'baz'}}, ['foo','bar']));
Run Code Online (Sandbox Code Playgroud)


Ted*_*opp 6

您可以创建一个基于属性名称数组访问元素的通用方法,该属性名称数组被解释为通过属性的路径:

function getValue(data, path) {
    var i, len = path.length;
    for (i = 0; typeof data === 'object' && i < len; ++i) {
        data = data[path[i]];
    }
    return data;
}
Run Code Online (Sandbox Code Playgroud)

然后你可以用:

var a = getValue(b, ["c", "d"]);
Run Code Online (Sandbox Code Playgroud)