根据索引数组从对象中获取特定的javascript值

时间:2012-10-08 16:07:41

标签: javascript underscore.js

给定一个这样的嵌套对象:

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实用程序库中完成,例如jQuerylo-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

如果函数足够智能以确定何时需要数组中的数字索引,那将是有帮助的。我不确定其他注意事项可能会引起关注。

对于我想象已经巧妙解决的问题,这是一个相当长的问题,但我想发布这个,因为我有兴趣看看那里有什么解决方案。

4 个答案:

答案 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;
}

编辑:

我已经遇到过几次解决这个问题的实现,包括:

  1. Ben Alman的getObject插件(Github)。
  2. 我推出了一个 - 请参阅gist
  3. 编辑(2014)

    我还会注意到相对较新的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"