使用点表示法字符串访问对象子属性

msa*_*jay 102 javascript jquery

我暂时坚持看似简单的JavaScript问题,但也许我只是错过了正确的搜索关键字!

假设我们有一个对象

var r = { a:1, b: {b1:11, b2: 99}};
Run Code Online (Sandbox Code Playgroud)

有几种方法可以访问99:

r.b.b2
r['b']['b2']
Run Code Online (Sandbox Code Playgroud)

我想要的是能够定义一个字符串

var s = "b.b2";
Run Code Online (Sandbox Code Playgroud)

然后使用访问99

r.s or r[s] //(which of course won't work)
Run Code Online (Sandbox Code Playgroud)

一种方法是为它编写一个函数,在字符串上拆分字符串,也可以递归/迭代地获取属性.但是有更简单/更有效的方法吗?在这里的任何jQuery API中有用吗?

And*_*y E 114

这是我刚才写的一个天真的函数,但它适用于基本的对象属性:

function getDescendantProp(obj, desc) {
    var arr = desc.split(".");
    while(arr.length && (obj = obj[arr.shift()]));
    return obj;
}

console.log(getDescendantProp(r, "b.b2"));
//-> 99
Run Code Online (Sandbox Code Playgroud)

虽然有些答案将此扩展为"允许"数组索引访问,但这并不是必需的,因为您可以使用此方法使用点表示法指定数字索引:

getDescendantProp({ a: [ 1, 2, 3 ] }, 'a.2');
//-> 3
Run Code Online (Sandbox Code Playgroud)

  • @user1912899:这不太一样,但可能更健壮一点,因为它会抛出错误(而我的只会返回“未定义”)。我想这取决于你的喜好。JSHint 只是抱怨循环条件中的赋值,可以使用“boss”选项禁用它。 (2认同)

Amm*_*CSE 92

在传递对象时将其拆分减少initalValue

var r = { a:1, b: {b1:11, b2: 99}};
var s = "b.b2";

var value = s.split('.').reduce(function(a, b) {
  return a[b];
}, r);

console.log(value);
Run Code Online (Sandbox Code Playgroud)

更新 (感谢TeChn4K发布的评论)

使用ES6语法,它甚至更短

var r = { a:1, b: {b1:11, b2: 99}};
var s = "b.b2";

var value = s.split('.').reduce((a, b) => a[b], r);

console.log(value);
Run Code Online (Sandbox Code Playgroud)

  • 使用ES6语法更短:让value = s.split('.').reduce((a,b)=> a [b],r) (11认同)
  • 对于您可能尝试查找对象的不存在的子值的情况(即:`c.c1`)的小改进.要捕获这个,只需在返回值中添加一个检查,如下所示:`return(a!= undefined)?a [b]:a;` (2认同)

Mat*_*zol 23

您可以使用lodash get()和set()方法.

入门

var object = { 'a': [{ 'b': { 'c': 3 } }] };

_.get(object, 'a[0].b.c');
// ? 3
Run Code Online (Sandbox Code Playgroud)

设置

var object = { 'a': [{ 'b': { 'c': 3 } }] };

_.set(object, 'a[0].b.c', 4);
console.log(object.a[0].b.c);
// ? 4
Run Code Online (Sandbox Code Playgroud)


Ror*_*san 19

如果您的场景中可以将整个数组变量放入字符串中,则可以使用该eval()函数.

var r = { a:1, b: {b1:11, b2: 99}};
var s = "r.b.b2";
alert(eval(s)); // 99
Run Code Online (Sandbox Code Playgroud)

我能感觉到人们惊恐万分

  • +1用于预测我的re丝. (20认同)
  • 遗憾的是,*reel*问题是使用`eval`会阻止编译器进行某些词法优化.这意味着,'eval`本身不仅速度慢,而且还会减慢它周围的代码速度.哦......还有双关语. (6认同)
  • 哦,我知道`eval()`的陷阱.事实上,我正在寻找一个电线羊毛淋浴,因为我觉得它很脏,甚至推荐它.安迪,我给你的答案+1了,因为它很容易就是这里最优雅的. (3认同)

Jas*_*ore 16

扩展@ JohnB的答案,我也添加了一个setter值.检查一下plunkr

http://plnkr.co/edit/lo0thC?p=preview

在此输入图像描述

function getSetDescendantProp(obj, desc, value) {
  var arr = desc ? desc.split(".") : [];

  while (arr.length && obj) {
    var comp = arr.shift();
    var match = new RegExp("(.+)\\[([0-9]*)\\]").exec(comp);

    // handle arrays
    if ((match !== null) && (match.length == 3)) {
      var arrayData = {
        arrName: match[1],
        arrIndex: match[2]
      };
      if (obj[arrayData.arrName] !== undefined) {
        if (typeof value !== 'undefined' && arr.length === 0) {
          obj[arrayData.arrName][arrayData.arrIndex] = value;
        }
        obj = obj[arrayData.arrName][arrayData.arrIndex];
      } else {
        obj = undefined;
      }

      continue;
    }

    // handle regular things
    if (typeof value !== 'undefined') {
      if (obj[comp] === undefined) {
        obj[comp] = {};
      }

      if (arr.length === 0) {
        obj[comp] = value;
      }
    }

    obj = obj[comp];
  }

  return obj;
}
Run Code Online (Sandbox Code Playgroud)

  • 我试图调整 Andy E 的解决方案以获得一套,然后我向下滚动并找到了这个。插入这个功能,看着我所有的测试都变绿了。谢谢。 (2认同)

Nic*_*tti 8

这是我能做的最简单的事情:

var accessProperties = function(object, string){
   var explodedString = string.split('.');
   for (i = 0, l = explodedString.length; i<l; i++){
      object = object[explodedString[i]];
   }
   return object;
}
var r = { a:1, b: {b1:11, b2: 99}};

var s = "b.b2";
var o = accessProperties(r, s);
alert(o);//99
Run Code Online (Sandbox Code Playgroud)

  • +1,这非常像我的解决方案,有一个显着的区别.如果其中一个属性(除了最后一个)不存在,您将抛出错误.我将返回`undefined`.两种解决方案在不同场景中都很有用 (2认同)

Man*_*ijn 5

你也可以这样做

var s = "['b'].b2";
var num = eval('r'+s);
Run Code Online (Sandbox Code Playgroud)