programing

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

starjava 2023. 8. 15. 09:41
반응형

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

저는 일시적으로 매우 간단한 자바스크립트 문제에 시달리고 있지만, 아마도 올바른 검색 키워드를 놓치고 있는 것 같습니다!

우리에게 목표가 있다고 가정해 보세요.

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

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

이전 버전

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

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 값도 추가하였습니다.플런크랫을 확인해 보세요.

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

다음은 배열로 재귀하고 모든 값을 반환하는 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
}

그래서 이것을 고려할 때.target:

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

다음을 얻을 수 있습니다.

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

지원되는 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;

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

Regex를 수행하는 데 더 효율적인 방법이 있을 수 있지만, 그것은 소형입니다.

이제 다음과 같은 작업을 수행할 수 있습니다.

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

Andy E's, Jason More's 및 나만의 솔루션에 대한 성능 테스트는 http://jsperf.com/propertyaccessor 에서 이용할 수 있습니다.수집된 데이터에 추가하기 위해 사용자의 브라우저를 사용하여 자유롭게 테스트를 실행하십시오.

예후는 확실해요, 앤디 E의 해결책이 지금까지 가장 빨라요!

관심 있는 분들을 위해, 여기 원래 질문에 대한 제 해결책의 코드가 있습니다.

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

짧은 대답: 아니요, 네이티브는 없습니다..access원하는 대로 작동합니다.당신이 정확히 언급했듯이, 당신은 문자열을 분할하고 그 부분에 대해 루프/체크하는 당신만의 함수를 정의해야 할 것입니다.

물론, 여러분이 항상 할 수 있는 것은 (비록 나쁜 관행으로 여겨지더라도) 사용하는 것입니다.eval().

맘에 들다

var s = 'b.b2';

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

여기에 @andy의 대답보다 조금 더 나은 방법이 있습니다, 어디에서.obj(선택 사항)은 선택 사항이며, 다음으로 돌아갑니다.window제공되지 않은 경우..

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

반응형