在javascript中如何动态获取对象的嵌套属性

时间:2011-08-02 00:42:05

标签: javascript object

var arr = { foo : 1, bar: { baz : 2 }, bee : 3 }

function getter(variable) {
  return arr[variable];
}

如果我想'foo'vs'bee',我可以做arr[variable] - 这很容易,而且功能就是这样。

但是,如果我想获得arr.bar.baz AKA arr[bar][baz]

,该怎么办?

我可以传递给getter函数,让我这样做,(当然也让我使用相同的函数获得非嵌套属性)。

我尝试了getter('bar.baz')getter('[bar][baz]'),但这些都没有用。

我想我可以解析点或括号(例如:In javascript, test for property deeply nested in object graph?)。有更干净的方式吗? (当然除了eval。)

特别是因为我需要在一个循环中为一堆数组元素多次正确地设置深度。

10 个答案:

答案 0 :(得分:39)

您可以使用基于路径字符串的深度访问功能。请注意,您不能在属性名称中包含任何句点。

function getPropByString(obj, propString) {
    if (!propString)
        return obj;

    var prop, props = propString.split('.');

    for (var i = 0, iLen = props.length - 1; i < iLen; i++) {
        prop = props[i];

        var candidate = obj[prop];
        if (candidate !== undefined) {
            obj = candidate;
        } else {
            break;
        }
    }
    return obj[props[i]];
}

var obj = {foo: {bar: {baz: 'x'}}};

alert(getPropByString(obj, 'foo.bar.baz')); // x
alert(getPropByString(obj, 'foo.bar.baz.buk')); // undefined

如果访问字符串为空,则返回该对象。否则,继续沿着访问路径前进,直到最后一个访问者。如果这是一个ojbect,则返回最后的object[accessor]值。否则,返回undefined。

答案 1 :(得分:18)

使用lodash库方法将是一种更好的方法: - https://lodash.com/docs#get

_.get(arr, 'bar.baz'); //returns 2;
_.get(arr, 'bar.baz[5].bazzz'); //returns undefined wont throw error;
_.get(arr, 'bar.baz[5].bazzz', 'defaultvalue'); // Returns defaultValue because result is undefined 

答案 2 :(得分:9)

如何将getter函数签名更改为getter('bar', 'baz')而不是

function getter() {
  var v = arr;
  for(var i=0; i< arguments.length; i++) {
    if(!v) return null;
    v = v[arguments[i]];
  }
  return v;
}

PS。没有测试,但你明白了;)

答案 3 :(得分:1)

您可以访问可以传递任意数量字符串的函数参数。 我还建议使用arr作为参数以获得更好的封装:

function getter() {
    var current = arguments[0];
    for(var i = 1; i < arguments.length; i++) {
        if(current[arguments[i]]) {
            current = current[arguments[i]];
        } else {
            return null;
        }
    }
    return current;
}

var arr = { foo : 1, bar: { baz : 2 }, bee : 3 };
var baz = getter(arr, 'bar', 'baz');

答案 4 :(得分:1)

Theres定义了一个函数on this blog来安全地从JS对象中读取嵌套属性

它允许您挖掘对象的属性......即

safeRead(arr, 'foo', 'bar', 'baz');

如果对象链的任何部分为null或未定义,则返回空字符串....

答案 5 :(得分:1)

我最近开发了自己的Object方法来获取嵌套在对象和数组中的对象属性,无论它有多深。它使用单行递归方法。看看这个。

Object.prototype.getNestedValue = function(...a) {
  return a.length > 1 ? (this[a[0]] !== void 0 && this[a[0]].getNestedValue(...a.slice(1))) : this[a[0]];
};

var myObj = { foo : 1, bar: { baz : 2 }, bee : 3 },
   bazval = myObj.getNestedValue("bar","baz");

document.write(bazval);

现在让我们检查一个更深层次的嵌套数组对象组合数据结构

Object.prototype.getNestedValue = function(...a) {
  return a.length > 1 ? (this[a[0]] !== void 0 && this[a[0]].getNestedValue(...a.slice(1))) : this[a[0]];
};

var myArr = [{fox: [{turn:[857, 432]}]}, {sax: [{pana:[777, 987]}]}, {ton: [{joni:[123, 567]}]}, {piu: [{burn:[666, 37]}]}, {sia: [{foxy:[404, 696]}]}];
  
document.write(myArr.getNestedValue(3,"piu",0,"burn",1));

我相信能够将搜索参数动态传递给现有的数组方法会使搜索,过滤或替换深层嵌套结构等操作变得非常容易。

答案 6 :(得分:1)

一种递归方式:

   function getValue(obj, path) {
        if (!path) return obj;
        const properties = path.split('.');
        return getValue(obj[properties.shift()], properties.join('.'))
    }

    const myObj = {
        foo: {
            bar: {
                value: 'good'
            }
        }
    }

    console.log(getValue(myObj, 'foo.bar.value')); // good

答案 7 :(得分:1)

以上答案仅帮助您访问嵌套对象,但是您可能还想访问对象/数组数据类型中的数据。你可以试试这个递归方法:

const getValue = (obj, key) => {
  const keyParts = key.split(".");
  return getValueHelper(obj, keyParts);
};

const getValueHelper = (obj, keyParts) => {
  if (keyParts.length == 0) return obj;
  let key = keyParts.shift();
  if (Array.isArray(obj[key])) {
    return obj[key].map((x) => getValueHelper(x, [...keyParts])).flat();
  }
  return getValueHelper(obj[key], [...keyParts]);
};


//Examples

let data1 = {
  a: [{ b: { c: [{ d: [{ e: 1 }] }] } }, { b: { c: [{ d: [{ e: 2 }] }] } }],
};

console.log(getValue(data1, "a.b.c.d.e"));

//Output
//[ 1, 2 ]

let data2 = {
  a:{b:1},
};

console.log(getValue(data2, "a.b"));
//Output
//1

附言删除 .flat() 以获得所需的数组输出。

答案 8 :(得分:0)

为您提供一个班轮

const mock = {
  target: {
    "prop1": {
      "prop2": {
        "prop3": "sad"
      }
    }
  },
  path: "prop1.prop2.prop3",
  newValue: "happy"
};

mock.path.split(".").reduce(
  (acc, curr, i, src) =>
    (curr === src[src.length - 1]) ? acc[src[src.length - 1]] = mock.newValue : acc[curr], mock.target);


console.log(mock.target); //? { prop1: { prop2: { prop3: 'happy' } } }

答案 9 :(得分:0)

userIds