我有基于json的数据结构,对象包含嵌套对象。为了访问特定的数据元素,我一直在链接对象属性的引用。例如:
var a = b.c.d;
如果未定义b或b.c,则会失败并显示错误。但是,我希望得到一个值,如果它存在,否则只是未定义。在不检查链中的每个值是否存在的情况下,最好的方法是什么?
我想尽可能保持这种方法的一般性,所以我不必添加大量的辅助方法,如:
var a = b.getD();
或
var a = helpers.getDFromB(b);
我也想尝试避免try / catch构造,因为这不是错误所以使用try / catch似乎是错误的。那是合理的吗?
有什么想法吗?
答案 0 :(得分:11)
标准方法:
var a = b && b.c && b.c.d && b.c.d.e;
非常快但不太优雅(特别是使用较长的属性名称)。
使用函数遍历JavaScipt对象属性既不高效也不优雅。
请改为尝试:
try { var a = b.c.d.e; } catch(e){}
如果您确定先前未使用a
或
try { var a = b.c.d.e; } catch(e){ a = undefined; }
如果您之前已经分配了它。
这可能比第一个选项更快。
答案 1 :(得分:5)
您可以创建一个基于属性名称数组访问元素的通用方法,该属性名称数组被解释为属性的路径:
function getValue(data, path) {
var i, len = path.length;
for (i = 0; typeof data === 'object' && i < len; ++i) {
data = data[path[i]];
}
return data;
}
然后你可以用:
来调用它var a = getValue(b, ["c", "d"]);
答案 2 :(得分:3)
这是一个老问题,现在有了es6功能,这个问题可以更容易解决。
const idx = (p, o) => p.reduce((xs, x) => (xs && xs[x]) ? xs[x] : null, o);
感谢@sharifsbeat为此solution。
答案 3 :(得分:0)
如果您希望动态访问手头有不规则数量的属性,那么在ES6中您可以轻松地执行以下操作;
function getNestedValue(o,...a){
var val = o;
for (var prop of a) val = typeof val === "object" &&
val !== null &&
val[prop] !== void 0 ? val[prop]
: undefined;
return val;
}
var obj = {a:{foo:{bar:null}}};
console.log(getNestedValue(obj,"a","foo","bar"));
console.log(getNestedValue(obj,"a","hop","baz"));
答案 4 :(得分:0)
可能它可能很简单:
{{1}}
等等。
答案 5 :(得分:0)
获取path
的{{1}}处的值。如果已解析的值为object
,则会在其位置返回undefined
。
在ES6中,我们可以从
defaultValue
下面的代码段获取嵌套属性。
Object
&#13;
答案 6 :(得分:0)
一个老问题,现在我们经常有Typescript项目,以至于这个问题似乎无关紧要,但是我到这里来寻找相同的东西,所以我做了一个简单的函数来做。对于我来说,您对不使用try / catch的想法过于严格,毕竟寻找undefined.x
仍然会导致错误。
因此,这就是我的方法。
function getSafe (obj, valuePath) {
try { return eval("obj." + valuePath); }
catch (err) { return null; }
}
要使用此功能,我们必须传递对象。我试图避免这种情况,但是没有其他方法可以从另一个函数中获取作用域(这里有很多问题)。 还有一个小测试集,看看我们能得到什么:
let outsideObject = {
html: {
pageOne: {
pageTitle: 'Lorem Ipsum!'
}
}
};
function testme() {
let insideObject = { a: { b: 22 } };
return {
b: getSafe(insideObject, "a.b"), // gives: 22
e: getSafe(insideObject, "a.b.c.d.e"), // gives: null
pageTitle: getSafe(outsideObject, "html.pageOne.pageTitle"), // gives: Lorem Ipsum!
notThere: getSafe(outsideObject, "html.pageOne.pageTitle.style") // gives: undefined
}
}
testme();
更新:
关于eval
的使用,我认为eval是一种要谨慎使用的工具,而不是魔鬼本身。在这种方法中,用户不会干扰评估,因为开发人员正在按其名称查找属性。
答案 7 :(得分:0)
如果您关心语法,这是Hosar答案的更简洁版本:
function safeAccess(path, object) {
if (object) {
return path.reduce(
(accumulator, currentValue) => (accumulator && accumulator[currentValue] ? accumulator[currentValue] : null),
object,
);
} else {
return null;
}
}
答案 8 :(得分:0)
这里的答案是好的裸机解决方案。但是,如果您只想使用经过尝试且正确的软件包,建议您使用lodash。
使用ES6,您可以运行以下
import _ from 'lodash'
var myDeepObject = {...}
value = _.get(myDeepObject, 'maybe.these.path.exist', 'Default value if not exists')
答案 9 :(得分:0)
对于这种情况,我将粘贴几乎在所有项目中使用的功能作为实用程序。
public static is(fn: Function, dv: any) {
try {
if (fn()) {
return fn()
} else {
return dv
}
} catch (e) {
return dv
}
}
因此,第一个参数是回调,第二个参数是默认值(如果由于某些错误而无法提取数据)。
我在所有地方都这样称呼它:
var a = is(()=> a.b.c, null);
答案 10 :(得分:0)
ECMAScript2020,并且在Node v14中具有optional chaining运算符(我也看到它称为安全导航运算符),这可以使您的示例编写为:
var a = b?.c?.d;
来自MDN docs:
可选的链接运算符(?。)允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。 ?。操作符的功能类似于。链接运算符,除了在引用为空(空或未定义)的情况下不会引起错误外,表达式会使用返回值未定义来短路。与函数调用一起使用时,如果给定的函数不存在,它将返回undefined。
答案 11 :(得分:-1)
const getValue = (obj, property, defaultValue) => (
property.split('.').reduce((item, key) => {
if (item && typeof item === 'object' && key in item) {
return item[key];
}
return defaultValue;
}, obj)
)
const object = {'a':{'b':{'c':3}}};
getValue(object, 'a.b.c'); // 3
getValue(object, 'a.b.x'); // undefined
getValue(object, 'a.b.x', 'default'); // 'default'
getValue(object, 'a.x.c'); // undefined