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

时间:2022-10-20 22:29:38

This question already has an answer here:

这个问题已经有了答案:

I'm temporarily stuck with what appears to be a very simple JavaScript problem, but maybe I'm just missing the right search keywords!

我暂时被一个看似简单的JavaScript问题困住了,但也许我只是错过了正确的搜索关键词!

Say we have an object

假设我们有一个物体

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

There are several ways to access the 99:

有几种方法可以访问99:

r.b.b2
r['b']['b2']

What I want is to be able to define a string

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

var s = "b.b2";

and then access the 99 using

然后使用99。

r.s or r[s] //(which of course won't work)

One way is to write a function for it that splits the string on dot and maybe recursively/iteratively gets the property. But is there any simpler/more efficient way? Anything useful in any of the jQuery APIs here?

一种方法是为它写一个函数,它可以在点上分割字符串,或者递归地/迭代地获取属性。但是有更简单/更有效的方法吗?在jQuery api中有什么有用的吗?

13 个解决方案

#1


101  

Here's a naive function I wrote a while ago, but it works for basic object properties:

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

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

console.log(getDescendantProp(r, "b.b2"));
//-> 99

Although there are answers that extend this to "allow" array index access, that's not really necessary as you can just specify numerical indexes using dot notation with this method:

虽然有一些答案可以扩展到“允许”数组索引访问,但这并不是必须的,因为你可以使用点符号来指定数值索引:

getDescendantProp({ a: [ 1, 2, 3 ] }, 'a.2');
//-> 3

#2


79  

split and reduce while passing the object as the initalValue

将对象作为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);

Update (thanks to comment posted by TeChn4K)

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

With ES6 syntax, it is even shorter

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

#3


17  

If it's possible in your scenario that you could put the entire array variable you're after into a string you could use the eval() function.

如果在您的场景中可以将您要查找的整个数组变量放入一个字符串中,那么可以使用eval()函数。

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

I can feel people reeling in horror

我能感觉到人们在恐惧中挣扎。

#4


16  

You can use lodash get() and set() methods.

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

Getting

得到

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

_.get(object, 'a[0].b.c');
// → 3

Setting

设置

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

_.set(object, 'a[0].b.c', 4);
console.log(object.a[0].b.c);
// → 4

#5


12  

Extending @JohnB's answer, I added a setter value as well. Check out the plunkr at

扩展了@JohnB的答案,我还添加了一个setter值。查看柱塞

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

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

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

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

#6


8  

This is the simplest i could do:

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

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

#7


5  

you could also do

你也可以做

var s = "['b'].b2";
var num = eval('r'+s);

#8


2  

I don't know a supported jQuery API function but I have this function:

我不知道一个支持的jQuery API函数,但是我有这个函数:

    var ret = data; // Your object
    var childexpr = "b.b2"; // Your expression

    if (childexpr != '') {
        var childs = childexpr.split('.');
        var i;
        for (i = 0; i < childs.length && ret != undefined; i++) {
            ret = ret[childs[i]];
        }
    }

    return ret;

#9


2  

I've extended Andy E's answer, so that it can also handle arrays:

我扩展了Andy E的答案,这样它也可以处理数组:

function getDescendantProp(obj, desc) {
    var arr = desc.split(".");

    //while (arr.length && (obj = obj[arr.shift()]));

    while (arr.length && obj) {
        var comp = arr.shift();
        var match = new RegExp("(.+)\\[([0-9]*)\\]").exec(comp);
        if ((match !== null) && (match.length == 3)) {
            var arrayData = { arrName: match[1], arrIndex: match[2] };
            if (obj[arrayData.arrName] != undefined) {
                obj = obj[arrayData.arrName][arrayData.arrIndex];
            } else {
                obj = undefined;
            }
        } else {
            obj = obj[comp]
        }
    }

    return obj;
}

There are probably more efficient ways to do the Regex, but it's compact.

可能有更有效的方法来完成Regex,但是它是紧凑的。

You can now do stuff like:

你现在可以这样做:

var model = {
    "m1": {
        "Id": "22345",
        "People": [
            { "Name": "John", "Numbers": ["07263", "17236", "1223"] },
            { "Name": "Jenny", "Numbers": ["2", "3", "6"] },
            { "Name": "Bob", "Numbers": ["12", "3333", "4444"] }
         ]
    }
}

// Should give you "6"
var x = getDescendantProp(model, "m1.People[1].Numbers[2]");

#10


2  

Here is an extension of Andy E's code, that recurses into arrays and returns all values:

这是Andy E的代码的扩展,它递归到数组中并返回所有值:

function GetDescendantProps(target, pathString) {
    var arr = pathString.split(".");
    while(arr.length && (target = target[arr.shift()])){
        if (arr.length && target.length && target.forEach) { // handle arrays
            var remainder = arr.join('.');
            var results = [];
            for (var i = 0; i < target.length; i++){
                var x = this.GetDescendantProps(target[i], remainder);
                if (x) results = results.concat(x);
            }
            return results;
        }
    }
    return (target) ? [target] : undefined; //single result, wrap in array for consistency
}

So given this target:

鉴于这一目标:

var t = 
{a:
    {b: [
            {'c':'x'},
            {'not me':'y'},
            {'c':'z'}
        ]
    }
};

We get:

我们得到:

GetDescendantProps(t, "a.b.c") === ["x", "z"]; // true

#11


2  

Performance tests for Andy E's, Jason More's, and my own solution are available at http://jsperf.com/propertyaccessor. Please feel free to run tests using your own browser to add to the data collected.

Andy E、Jason More和我自己的解决方案的性能测试可以在http://jsperf.com/propertyaccessor上找到。请随意使用您自己的浏览器运行测试,以添加到所收集的数据中。

The prognosis is clear, Andy E's solution is the fastest by far!

预后很明确,安迪的解决方案是目前最快的!

For anyone interested, here is the code for my solution to the original question.

对于任何有兴趣的人,这是我对原始问题的解决方案的代码。

function propertyAccessor(object, keys, array) {
    /*
    Retrieve an object property with a dot notation string.
    @param  {Object}  object   Object to access.
    @param  {String}  keys     Property to access using 0 or more dots for notation.
    @param  {Object}  [array]  Optional array of non-dot notation strings to use instead of keys.
    @return  {*}
    */
    array = array || keys.split('.')

    if (array.length > 1) {
        // recurse by calling self
        return propertyAccessor(object[array.shift()], null, array)
    } else {
        return object[array]
    }
}

#12


0  

Short answer: No, there is no native .access function like you want it. As you correctly mentioned, you would have to define your own function which splits the string and loops/checks over its parts.

简短的回答:不,没有本地的。访问功能就像你想要的那样。正如您正确地提到的,您必须定义自己的函数,该函数将字符串分割,并对其部分进行循环/检查。

Of course, what you always can do (even if its considered bad practice) is to use eval().

当然,您总是可以做的(即使它被认为是不好的实践)是使用eval()。

Like

就像

var s = 'b.b2';

eval('r.' + s); // 99

#13


0  

Here is a a little better way then @andy's answer, where the obj (context) is optional, it falls back to window if not provided..

这里有一个比@andy的答案更好的方法,在obj(上下文)是可选的地方,如果没有提供,它会返回到窗口。

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

#1


101  

Here's a naive function I wrote a while ago, but it works for basic object properties:

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

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

console.log(getDescendantProp(r, "b.b2"));
//-> 99

Although there are answers that extend this to "allow" array index access, that's not really necessary as you can just specify numerical indexes using dot notation with this method:

虽然有一些答案可以扩展到“允许”数组索引访问,但这并不是必须的,因为你可以使用点符号来指定数值索引:

getDescendantProp({ a: [ 1, 2, 3 ] }, 'a.2');
//-> 3

#2


79  

split and reduce while passing the object as the initalValue

将对象作为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);

Update (thanks to comment posted by TeChn4K)

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

With ES6 syntax, it is even shorter

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

#3


17  

If it's possible in your scenario that you could put the entire array variable you're after into a string you could use the eval() function.

如果在您的场景中可以将您要查找的整个数组变量放入一个字符串中,那么可以使用eval()函数。

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

I can feel people reeling in horror

我能感觉到人们在恐惧中挣扎。

#4


16  

You can use lodash get() and set() methods.

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

Getting

得到

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

_.get(object, 'a[0].b.c');
// → 3

Setting

设置

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

_.set(object, 'a[0].b.c', 4);
console.log(object.a[0].b.c);
// → 4

#5


12  

Extending @JohnB's answer, I added a setter value as well. Check out the plunkr at

扩展了@JohnB的答案,我还添加了一个setter值。查看柱塞

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

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

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

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

#6


8  

This is the simplest i could do:

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

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

#7


5  

you could also do

你也可以做

var s = "['b'].b2";
var num = eval('r'+s);

#8


2  

I don't know a supported jQuery API function but I have this function:

我不知道一个支持的jQuery API函数,但是我有这个函数:

    var ret = data; // Your object
    var childexpr = "b.b2"; // Your expression

    if (childexpr != '') {
        var childs = childexpr.split('.');
        var i;
        for (i = 0; i < childs.length && ret != undefined; i++) {
            ret = ret[childs[i]];
        }
    }

    return ret;

#9


2  

I've extended Andy E's answer, so that it can also handle arrays:

我扩展了Andy E的答案,这样它也可以处理数组:

function getDescendantProp(obj, desc) {
    var arr = desc.split(".");

    //while (arr.length && (obj = obj[arr.shift()]));

    while (arr.length && obj) {
        var comp = arr.shift();
        var match = new RegExp("(.+)\\[([0-9]*)\\]").exec(comp);
        if ((match !== null) && (match.length == 3)) {
            var arrayData = { arrName: match[1], arrIndex: match[2] };
            if (obj[arrayData.arrName] != undefined) {
                obj = obj[arrayData.arrName][arrayData.arrIndex];
            } else {
                obj = undefined;
            }
        } else {
            obj = obj[comp]
        }
    }

    return obj;
}

There are probably more efficient ways to do the Regex, but it's compact.

可能有更有效的方法来完成Regex,但是它是紧凑的。

You can now do stuff like:

你现在可以这样做:

var model = {
    "m1": {
        "Id": "22345",
        "People": [
            { "Name": "John", "Numbers": ["07263", "17236", "1223"] },
            { "Name": "Jenny", "Numbers": ["2", "3", "6"] },
            { "Name": "Bob", "Numbers": ["12", "3333", "4444"] }
         ]
    }
}

// Should give you "6"
var x = getDescendantProp(model, "m1.People[1].Numbers[2]");

#10


2  

Here is an extension of Andy E's code, that recurses into arrays and returns all values:

这是Andy E的代码的扩展,它递归到数组中并返回所有值:

function GetDescendantProps(target, pathString) {
    var arr = pathString.split(".");
    while(arr.length && (target = target[arr.shift()])){
        if (arr.length && target.length && target.forEach) { // handle arrays
            var remainder = arr.join('.');
            var results = [];
            for (var i = 0; i < target.length; i++){
                var x = this.GetDescendantProps(target[i], remainder);
                if (x) results = results.concat(x);
            }
            return results;
        }
    }
    return (target) ? [target] : undefined; //single result, wrap in array for consistency
}

So given this target:

鉴于这一目标:

var t = 
{a:
    {b: [
            {'c':'x'},
            {'not me':'y'},
            {'c':'z'}
        ]
    }
};

We get:

我们得到:

GetDescendantProps(t, "a.b.c") === ["x", "z"]; // true

#11


2  

Performance tests for Andy E's, Jason More's, and my own solution are available at http://jsperf.com/propertyaccessor. Please feel free to run tests using your own browser to add to the data collected.

Andy E、Jason More和我自己的解决方案的性能测试可以在http://jsperf.com/propertyaccessor上找到。请随意使用您自己的浏览器运行测试,以添加到所收集的数据中。

The prognosis is clear, Andy E's solution is the fastest by far!

预后很明确,安迪的解决方案是目前最快的!

For anyone interested, here is the code for my solution to the original question.

对于任何有兴趣的人,这是我对原始问题的解决方案的代码。

function propertyAccessor(object, keys, array) {
    /*
    Retrieve an object property with a dot notation string.
    @param  {Object}  object   Object to access.
    @param  {String}  keys     Property to access using 0 or more dots for notation.
    @param  {Object}  [array]  Optional array of non-dot notation strings to use instead of keys.
    @return  {*}
    */
    array = array || keys.split('.')

    if (array.length > 1) {
        // recurse by calling self
        return propertyAccessor(object[array.shift()], null, array)
    } else {
        return object[array]
    }
}

#12


0  

Short answer: No, there is no native .access function like you want it. As you correctly mentioned, you would have to define your own function which splits the string and loops/checks over its parts.

简短的回答:不,没有本地的。访问功能就像你想要的那样。正如您正确地提到的,您必须定义自己的函数,该函数将字符串分割,并对其部分进行循环/检查。

Of course, what you always can do (even if its considered bad practice) is to use eval().

当然,您总是可以做的(即使它被认为是不好的实践)是使用eval()。

Like

就像

var s = 'b.b2';

eval('r.' + s); // 99

#13


0  

Here is a a little better way then @andy's answer, where the obj (context) is optional, it falls back to window if not provided..

这里有一个比@andy的答案更好的方法,在obj(上下文)是可选的地方,如果没有提供,它会返回到窗口。

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