【问题标题】:In javascript how can I dynamically get a nested property of an object在javascript中如何动态获取对象的嵌套属性
【发布时间】:2011-10-17 21:05:59
【问题描述】:
var arr = { foo : 1, bar: { baz : 2 }, bee : 3 }

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

如果我想要 'foo' 和 '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。)

尤其是因为我需要在一个循环中为一堆数组元素正确设置很多次。

【问题讨论】:

  • 为什么不直接使用链接问题中的这种方法?
  • 主要是因为经常调用函数的开销,还有如果有更好的方法想学。
  • 另一种选择是将回调作为变量参数引用,如下所示: getter(obj => obj.foo.bar.baz) 然后在算法中调用它 getter(variable) { return variable (arr) } 可能会测试是否是一个字符串,只需使用 [ ] 符号或者它是否是函数调用它。

标签: javascript object


【解决方案1】:

let obj = {foo : {bar: {baz:1}}}; // -- 简单

console.log(eval('obj.foo.bar.baz')); //-- 1

// -- 更安全

val = "";
try {
    val = eval('Obj.foo.bar.baz')
}
catch(e) {
    val = "empty"
}

// -- val = 1

// -- 使用风险自负 ;)

【讨论】:

    【解决方案2】:

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

    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'
        }
      }
    };
    
    console.log(getPropByString(obj, 'foo.bar.baz')); // x
    console.log(getPropByString(obj, 'foo.bar.baz.buk')); // undefined

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

    【讨论】:

      【解决方案3】:

      以上答案仅帮助您访问嵌套对象,但您可能还希望访问对象/数组数据类型中的数据。你可以试试这个rec​​usive方法:

      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() 以获得所需的数组输出。

      【讨论】:

        【解决方案4】:
         function getPropertyByString(object, propString) {
          let value = object;
        
          const props = propString.split('.');
          for (let index = 0; index < props.length; index += 1) {
            if (props[index] === undefined) break;
            value = value[props[index]];
          }
          return value;
        };
        
        const object = {
          name: 'any_name',
          address: {
            number: 77,
            test: {
              name: 'test'
            }
          }
        }
        
        console.log(getPropertyByString(object, 'address.test.name'))
        // test
        

        【讨论】:

        • 请务必解释您的答案,以便其他人可以从中学习。
        • @AlexH 我试图让代码不言自明,但我很欣赏这个建议。
        【解决方案5】:

        使用 ES6:

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

        同:

        // var foo = 1;
        // var bar = {baz: 2};
        // var baz = 2;
        // var bee = 3;
        

        使用 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 
        

        【讨论】:

        • 谢谢,这正是我想要的。它的_.set朋友也很有用。
        【解决方案6】:

        递归方式:

           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】:

          一个一个班轮给你:

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

          【讨论】:

            【解决方案8】:

            我最近开发了自己的 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));

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

            【讨论】:

              【解决方案9】:

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

              它允许你挖掘一个对象的属性......即。

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

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

              【讨论】:

                【解决方案10】:

                您可以访问可以传递任意数量字符串的函数参数。 我还建议使用 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');
                

                【讨论】:

                  【解决方案11】:

                  将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。没有测试,但你明白了;)

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2018-11-30
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-08-25
                    • 2013-09-27
                    • 2022-01-24
                    • 2018-02-06
                    相关资源
                    最近更新 更多