给定一个这样的嵌套对象:
var cars = {
"bentley": {
"suppliers": [
{
"location": "England",
"name": "Sheffield Mines"}
]
// ...
}
};
和像这样["bentley", "suppliers", "0", "name"]
的数组,是否存在一个现有的函数,它将采用最深的元素,即pluck_innards(cars, ['bentley', "suppliers", "0", "name"])
,并返回“谢菲尔德矿山”。
换句话说,是否有一个函数(我将其命名为deep_pluck
)
deep_pluck(cars, ['bentley', 'suppliers', '0', 'name'])
=== cars['bentley']['suppliers']['0']['name']
在我看来,这很简单,但很常见,可能已经在其中一个Javascript实用程序库中完成,例如jQuery或lo-dash /下划线 - 但我还没有看到它
我的想法是微不足道的,包括:
function deep_pluck(array, identities) {
var this_id = identities.shift();
if (identities.length > 0) {
return deep_pluck(array[this_id], identities);
}
return array[this_id];
}
我发布了on jsFiddle。
如果函数足够智能以确定何时需要数组中的数字索引,那将是有帮助的。我不确定其他注意事项可能会引起关注。
对于我想象已经巧妙解决的问题,这是一个相当长的问题,但我想发布这个,因为我有兴趣看看那里有什么解决方案。
答案 0 :(得分:2)
如果您将数组索引作为数字0
传递,我认为您不会遇到问题。
这是您的函数的替代版本,没有递归:
function deep_pluck(object, identities) {
var result = object;
for(var i = 0; i < identities.length; i++) {
result = result[identities[i]];
}
return result;
}
这里的工作示例:http://jsfiddle.net/AmH2w/1/
答案 1 :(得分:1)
虽然不是通用库,但似乎CasperJS具有utils.getPropertyPath
函数的此类内容。
/**
* Retrieves the value of an Object foreign property using a dot-separated
* path string.
*
* Beware, this function doesn't handle object key names containing a dot.
*
* @param Object obj The source object
* @param String path Dot separated path, eg. "x.y.z"
*/
function getPropertyPath(obj, path) {
if (!isObject(obj) || !isString(path)) {
return undefined;
}
var value = obj;
path.split('.').forEach(function(property) {
if (typeof value === "object" && property in value) {
value = value[property];
} else {
value = undefined;
}
});
return value;
}
我已经遇到过几次解决这个问题的实现,包括:
我还会注意到相对较新的lodash.deep
。
答案 2 :(得分:1)
dotty.get(obj,pathspec)执行此操作,接受数组或虚线字符串作为pathspec。
Dotty是开源的,还有一个存在方法和一个推杆。
该方法是递归的,与你的想法非常相似,不同之处在于dotty包含对null / undefined对象的测试,因此它不会为尝试访问不存在的元素而抛出异常。
dotty.get() source from the docs发布在以下位置:
var get = module.exports.get = function get(object, path) {
if (typeof path === "string") {
path = path.split(".");
}
if (!(path instanceof Array) || path.length === 0) {
return;
}
path = path.slice();
var key = path.shift();
if (typeof object !== "object" || object === null) {
return;
}
if (path.length === 0) {
return object[key];
}
if (path.length) {
return get(object[key], path);
}
};
答案 3 :(得分:0)
以下是使用reduce
的简短ES6实现:
function get(obj, keyPath) {
return keyPath
.split(".")
.reduce((prev, curr) => prev[curr], obj);
}
用法:
get(cars, "bentley.suppliers.0.name") // -> "Sheffield Mines"