使用點表示法字符串[duplicate]訪問對象子屬性

[英]Access object child properties using a dot notation string [duplicate]


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

enter image description here

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

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2011/11/08/b0a6403772e90a61589e587a656a2eac.html



 
  © 2014-2022 ITdaan.com 联系我们: