code

점 표기법 문자열을 사용하여 개체 자식 속성에 액세스

codestyles 2020. 8. 17. 08:58
반응형

점 표기법 문자열을 사용하여 개체 자식 속성에 액세스


이 질문에 이미 답변이 있습니다.

나는 일시적으로 매우 간단한 자바 스크립트 문제로 보이는 문제에 갇혀 있지만, 아마도 올바른 검색 키워드를 놓치고있을 수 있습니다!

우리에게 물건이 있다고

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

99에 액세스하는 방법에는 여러 가지가 있습니다.

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

내가 원하는 것은 문자열을 정의 할 수있는 것입니다.

var s = "b.b2";

다음을 사용하여 99에 액세스하십시오.

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

한 가지 방법은 문자열을 점으로 분할하고 재귀 적으로 / 반복적으로 속성을 가져 오는 함수를 작성하는 것입니다. 그러나 더 간단하고 효율적인 방법이 있습니까? 여기에 jQuery API에서 유용한 것이 있습니까?


다음은 내가 얼마 전에 작성한 순진한 함수이지만 기본 객체 속성에 대해 작동합니다.

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

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

배열 인덱스 액세스를 "허용"하도록 확장하는 답변이 있지만이 방법으로 점 표기법을 사용하여 숫자 인덱스를 지정할 수 있으므로 실제로는 필요하지 않습니다.

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

개체를 전달하는 동안 분할 축소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);

업데이트 (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);


lodash get () 및 set () 메서드를 사용할 수 있습니다 .

얻기

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

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

환경

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

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

시나리오에서 전체 배열 변수를 문자열에 넣을 수 있다면 eval()함수를 사용할 수 있습니다 .

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

사람들이 공포에 떨리는 것을 느낄 수 있습니다.


@JohnB의 답변을 확장하여 setter 값도 추가했습니다. 에서 plunkr를 확인하십시오

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

이것은 내가 할 수있는 가장 간단한 방법입니다.

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

당신은 또한 할 수 있습니다

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

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

    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;

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

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.

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]");

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

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

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.

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

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().

Like

var s = 'b.b2';

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

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..

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

참고URL : https://stackoverflow.com/questions/8051975/access-object-child-properties-using-a-dot-notation-string

반응형