【问题标题】:dynamic access to an array in Javascript在Javascript中动态访问数组
【发布时间】:2014-12-18 15:12:40
【问题描述】:

也许已经有解决方案,但我找不到。我尝试动态访问多维数组中的不同插槽,但面临不同深度的挑战。基本上,它看起来像这样:

var source = [];
source['lvl1'] = [];
source['lvl1']['lvl2a'] = [];
source['lvl1']['lvl2a']['lvl3'] = "ping";
source['lvl1']['lvl2b'] = "pong";

如果深度是固定的,我可以这样写代码:

var path1 = ["lvl1","lvl2a","lvl3"];
var path2 = ["lvl1","lvl2b"];

console.log(source[path1[0]][path1[1]][path[2]]); // => ping
console.log(source[path2[0]][path2[1]]); // => pong

我的问题是编写适用于两种变体的代码。这会起作用:

switch(path.length)
{
  case 1:
    console.log(source[path[0]]);
    break;
  case 2: 
    console.log(source[path[0]][path[1]]);
    break;
  case 3:
    console.log(source[path[0]][path[1]][path[2]]);
    break;
}

但这既不高效也不优雅。有人有其他解决方案,例如与某种循环一起工作吗?!?

谢谢 托马斯

【问题讨论】:

  • 请注意,您并没有像这样使用数组,而是向对象添加属性,javascript 没有关联数组。
  • 不清楚您在这里实际尝试做什么。
  • 最后,我尝试开发一个通用的json配置文件编辑器。我有某种模式文件来描述 json,然后我的脚本一方面创建一个 html 表单来编辑数据,另一方面将更改写回 json 结构。读取并不困难,但更新结构中的值是困难的。

标签: javascript arrays


【解决方案1】:

这个问题很久以前就已经回答过了,但我想展示一个使用数组缩减器的非常简单的单行解决方案:

const getRoute = (o, r) => r.split(".").reduce((c, s) => c[s], o);

let q = {a:{b:{c:{d:"hello world"}}}};

console.log(getRoute(q, 'a.b.c.d'));

这可能对其他人有帮助:)

【讨论】:

    【解决方案2】:

    如果你确定数组中的所有值都存在,那么你可以简单地使用Array.prototype.reduce,像这样

    console.log(path1.reduce(function(result, currentKey) {
        return result[currentKey];
    }, source));
    # ping
    

    你可以把它变成通用的,像这样

    function getValueFromObject(object, path) {
        return path.reduce(function(result, currentKey) {
            return result[currentKey];
        }, object);
    }
    

    然后像这样调用它

    console.assert(getValueFromObject(source, path1) === "ping");
    console.assert(getValueFromObject(source, path2) === "pong");
    

    注意:您需要确保source 是一个JavaScript 对象。您现在拥有的称为数组。

    var source = {};   # Note `{}`, not `[]`
    

    【讨论】:

    • OP 需要一个对象。不是数组,因为他使用的是键。
    • @AmitJoki 我不明白你,什么不是数组?你能解释一下吗?
    • 我删除了之前的评论,刷新页面。
    • @AmitJoki 不,该评论仅适用于第一条评论。
    • 当OP在做var source = []; source["key"]时,倾向于使用Array。在您编辑以使 source 成为对象之前,我的第一条评论也已被评论。
    【解决方案3】:

    您可以在记录之前循环并建立 source 的值。试试这个:

    var sourceValue = source[path[0]];
    for (var i = 1; i < path.length; i++) {
        sourceValue = sourceValue[path[i]];
    }
    console.log(sourceValue);
    

    这是一个 JSFiddle,它证明了这种方法是有效的。

    【讨论】:

    • 嗯,我得测试一下。实际上,我的主要目的不仅是读取一个值(适用于这种方法),而且是设置一个新值。如果我是对的,您可以通过将原始对象缩减为路径数组所描述的部分来提取值,但同时也会破坏原始对象。
    • 如果您循环到path.length-1,那么您将获得对所需值的容器的引用,并且可以对其进行修改。
    【解决方案4】:

    您可以从路径中获取值(测试代码):

    var getValue = function(path, context) {
        if ('object' !== typeof context) {
            throw new Error('The context must be an object; "' + typeof context + '" given instead.');
        }
        if ('string' !== typeof path) {
            throw new Error('The path must be a string; "' + typeof context + '" given instead.');
        }
    
        var fields = path.split('.'),
            getValueFromFields = function(fields, context) {
                var field = fields.shift();
    
                if (0 === fields.length) {
                    return context[field];
                }
    
                if ('object' !== typeof context[field]) {
                    throw new Error('The path "' + path + '" has no value.');
                }
    
                return getValueFromFields(fields, context[field]);
            }
        ;
    
        return getValueFromFields(fields, context);
    }
    
    var source = [];
    source['lvl1'] = [];
    source['lvl1']['lvl2a'] = [];
    source['lvl1']['lvl2a']['lvl3'] = "ping";
    source['lvl1']['lvl2b'] = "pong";
    
    console.log(getValue('lvl1.lvl2a.lvl3', source)); // ping
    console.log(getValue('lvl1.lvl2b', source));      // pong
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-23
      • 2021-12-05
      • 2010-09-06
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      相关资源
      最近更新 更多