8

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

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']

在我看来,这很简单,但很常见,可能已经在 J​​avascript 实用程序库之一中完成,例如jQuerylo-dash /underscore - 但我还没有看到它。

我的想法是微不足道的,大致如下:

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];
}

我已经在 jsFiddle 上发布了。

如果该函数足够聪明,可以识别何时需要数组中的数字索引,那当然会有所帮助。我不确定还有哪些其他警告可能是一个问题。

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

4

4 回答 4

2

如果您将数组索引作为 number 传递,我认为您不会遇到问题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/

于 2012-10-08T16:20:46.300 回答
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. 我滚动的一个 - 见要点

编辑 (2014)

我还要注意相对较新的lodash.deep.

于 2012-10-12T02:23:46.617 回答
1

dotty.get(obj, pathspec) 执行此操作,接受数组或点分字符串作为路径规范。

Dotty是开源的,也有一个 exists 方法和一个 putter。

该方法是递归的,与您的想法非常相似,除了 dotty 包含对 null/undefined 对象的测试,因此它不会在尝试访问不存在的元素时抛出异常。

来自文档的dotty.get() 源发布在下面:

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);
  }
};
于 2013-07-19T15:21:08.763 回答
0

这是一个简短的 ES6 实现,使用reduce

function get(obj, keyPath) {
    return keyPath
        .split(".")
        .reduce((prev, curr) => prev[curr], obj);
}

用法:

get(cars, "bentley.suppliers.0.name") // -> "Sheffield Mines"
于 2016-09-14T12:21:42.380 回答