programing

문자열 경로를 통해 중첩된 JavaScript 개체 및 배열 액세스

sourcetip 2022. 9. 19. 22:26
반응형

문자열 경로를 통해 중첩된 JavaScript 개체 및 배열 액세스

다음과 같은 데이터 구조를 가지고 있습니다.

var someObject = {
    'part1' : {
        'name': 'Part 1',
        'size': '20',
        'qty' : '50'
    },
    'part2' : {
        'name': 'Part 2',
        'size': '15',
        'qty' : '60'
    },
    'part3' : [
        {
            'name': 'Part 3A',
            'size': '10',
            'qty' : '20'
        }, {
            'name': 'Part 3B',
            'size': '5',
            'qty' : '20'
        }, {
            'name': 'Part 3C',
            'size': '7.5',
            'qty' : '20'
        }
    ]
};

그리고 다음 변수를 사용하여 데이터에 액세스하고 싶습니다.

var part1name = "part1.name";
var part2quantity = "part2.qty";
var part3name1 = "part3[0].name";

은 part1name으로 .someObject.part1.name의 값,즉 " 1 "Part 1"이다.60.60으로 .

순수 javascript 또는 JQuery 중 하나로 이를 달성할 수 있는 방법이 있습니까?

이미 가지고 있던 유사한 코드에 근거해 작성했습니다만, 정상적으로 동작하고 있는 것 같습니다.

Object.byString = function(o, s) {
    s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
    s = s.replace(/^\./, '');           // strip a leading dot
    var a = s.split('.');
    for (var i = 0, n = a.length; i < n; ++i) {
        var k = a[i];
        if (k in o) {
            o = o[k];
        } else {
            return;
        }
    }
    return o;
}

사용방법:

Object.byString(someObj, 'part3[0].name');

http://jsfiddle.net/alnitak/hEsys/에서 작업 데모를 보실 수 있습니다.

일부 편집자는 맨 왼쪽 인덱스가 개체 내에서 올바르게 중첩된 엔트리에 일치하지 않는 문자열을 전달하면 이 코드가 오류를 발생시키는 것을 발견했습니다.이는 타당한 우려 사항이지만 IMHO는 다음 사항을 통해 가장 잘 대처합니다.try / catch 발신시에 블록 .undefined유효하지 않은 인덱스의 경우.

은 현재 를 사용하여 됩니다._.get(obj, property)https://lodash.com/docs#get 를 참조해 주세요.

문서의 예:

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

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

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

_.get(object, 'a.b.c', 'default');
// → 'default'

사용하고 있는 솔루션은 다음과 같습니다.

function resolve(path, obj=self, separator='.') {
    var properties = Array.isArray(path) ? path : path.split(separator)
    return properties.reduce((prev, curr) => prev && prev[curr], obj)
}

사용 예:

// accessing property path on global scope
resolve("document.body.style.width")
// or
resolve("style.width", document.body)

// accessing array indexes
// (someObject has been defined in the question)
resolve("part3.0.size", someObject) // returns '10'

// accessing non-existent properties
// returns undefined when intermediate properties are not defined:
resolve('properties.that.do.not.exist', {hello:'world'})

// accessing properties with unusual keys by changing the separator
var obj = { object: { 'a.property.name.with.periods': 42 } }
resolve('object->a.property.name.with.periods', obj, '->') // returns 42

// accessing properties with unusual keys by passing a property name array
resolve(['object', 'a.property.name.with.periods'], obj) // returns 42

제한 사항:

  • 괄호를할 수 []인덱스의 간의 를 들어, 「」는 「」, 「」는 「」, 「」는 「」, 「」는 「」, 「」는 「」, 「」는 「」, 「」는 「」, 「」는 「」)..는 위와 는 위와 같이 정상적으로 동작합니다.

ES6: Vanila JS에서 한 줄만(오류 대신 찾을 수 없는 경우 null을 반환):

'path.string'.split('.').reduce((p,c)=>p&&p[c]||null, MyOBJ)

또는 다음 예시를 들 수 있습니다.

'a.b.c'.split('.').reduce((p,c)=>p&&p[c]||null, {a:{b:{c:1}}})

옵션 체인 연산자 사용:

'a.b.c'.split('.').reduce((p,c)=>p?.[c], {a:{b:{c:1}}})

false, 0 및 음수를 인식하고 기본값을 파라미터로 받아들이는 Ready to Use 함수의 경우:

const resolvePath = (object, path, defaultValue) => path
   .split('.')
   .reduce((o, p) => o ? o[p] : defaultValue, object)

사용하는 예:

resolvePath(window,'document.body') => <body>
resolvePath(window,'document.body.xyz') => undefined
resolvePath(window,'document.body.xyz', null) => null
resolvePath(window,'document.body.xyz', 1) => 1

보너스:

경로(@rob-gordon에 의해 요구됨)를 설정하려면 다음 명령을 사용합니다.

const setPath = (object, path, value) => path
   .split('.')
   .reduce((o,p,i) => o[p] = path.split('.').length === ++i ? value : o[p] || {}, object)

예:

let myVar = {}
setPath(myVar, 'a.b.c', 42) => 42
console.log(myVar) => {a: {b: {c: 42}}}

[]:사용하여 어레이에 액세스합니다.

const resolvePath = (object, path, defaultValue) => path
   .split(/[\.\[\]\'\"]/)
   .filter(p => p)
   .reduce((o, p) => o ? o[p] : defaultValue, object)

예:

const myVar = {a:{b:[{c:1}]}}
resolvePath(myVar,'a.b[0].c') => 1
resolvePath(myVar,'a["b"][\'0\'].c') => 1

문자열을 직접 해석해야 합니다.

function getProperty(obj, prop) {
    var parts = prop.split('.');

    if (Array.isArray(parts)) {
        var last = parts.pop(),
        l = parts.length,
        i = 1,
        current = parts[0];

        while((obj = obj[current]) && i < l) {
            current = parts[i];
            i++;
        }

        if(obj) {
            return obj[last];
        }
    } else {
        throw 'parts is not valid array';
    }
}

이를 위해서는 다음과 같은 도트 표기로 어레이 인덱스를 정의해야 합니다.

var part3name1 = "part3.0.name";

파싱이 쉬워집니다.

데모

오브젝트내의 어레이/어레이에도 대응합니다.유효하지 않은 값에 대해 방어합니다.

/**
 * Retrieve nested item from object/array
 * @param {Object|Array} obj
 * @param {String} path dot separated
 * @param {*} def default value ( if result undefined )
 * @returns {*}
 */
function path(obj, path, def){
    var i, len;

    for(i = 0,path = path.split('.'), len = path.length; i < len; i++){
        if(!obj || typeof obj !== 'object') return def;
        obj = obj[path[i]];
    }

    if(obj === undefined) return def;
    return obj;
}

//////////////////////////
//         TEST         //
//////////////////////////

var arr = [true, {'sp ace': true}, true]

var obj = {
  'sp ace': true,
  arr: arr,
  nested: {'dotted.str.ing': true},
  arr3: arr
}

shouldThrow(`path(obj, "arr.0")`);
shouldBeDefined(`path(obj, "arr[0]")`);
shouldBeEqualToNumber(`path(obj, "arr.length")`, 3);
shouldBeTrue(`path(obj, "sp ace")`);
shouldBeEqualToString(`path(obj, "none.existed.prop", "fallback")`, "fallback");
shouldBeTrue(`path(obj, "nested['dotted.str.ing'])`);
<script src="https://cdn.rawgit.com/coderek/e7b30bac7634a50ad8fd/raw/174b6634c8f57aa8aac0716c5b7b2a7098e03584/js-test.js"></script>

이건 아마 영원히 빛을 보지 못할 거야어쨌든 여기 있습니다.

  1. [] ('').
  2. .character성격
  3. 빈 문자열 제거
  4. 길( 그렇지 않으면 경로를 찾습니다(그렇지 않은 경우)을 찾아라.undefined)

(개체에 대한 경로를 찾으려면 다음 솔루션을 사용하십시오.)

// "one liner" (ES6)

const deep_value = (obj, path) => 
path
    .replace(/\[|\]\.?/g, '.')
    .split('.')
    .filter(s => s)
    .reduce((acc, val) => acc && acc[val], obj);
    
// ... and that's it.

var someObject = {
    'part1' : {
        'name': 'Part 1',
        'size': '20',
        'qty' : '50'
    },
    'part2' : {
        'name': 'Part 2',
        'size': '15',
        'qty' : '60'
    },
    'part3' : [
        {
            'name': 'Part 3A',
            'size': '10',
            'qty' : '20'
        }
        // ...
    ],
    'pa[rt3' : [
        {
            'name': 'Part 3A',
            'size': '10',
            'qty' : '20'
        }
        // ...
    ]
};

console.log(deep_value(someObject, "part1.name"));               // Part 1
console.log(deep_value(someObject, "part2.qty"));                // 60
console.log(deep_value(someObject, "part3[0].name"));            // Part 3A
console.log(deep_value(someObject, "part3[0].....name"));        // Part 3A - invalid blank paths removed
console.log(deep_value(someObject, "pa[rt3[0].name"));           // undefined - name does not support square brackets

eval 사용:

var part1name = eval("someObject.part1.name");

오류에 대해 정의되지 않은 상태로 반환하는 랩

function path(obj, path) {
    try {
        return eval("obj." + path);
    } catch(e) {
        return undefined;
    }
}

http://jsfiddle.net/shanimal/b3xTw/

평가의 힘을 발휘할 때는 상식과 주의를 기울여 주십시오.광선검과 비슷해요. 이걸 켜면 손발이 잘릴 확률이 90%나 돼요.모두를 위한 것은 아니다.

다음과 같은 간단한 방법으로 외부 JavaScript 라이브러리 없이 도트 표기법을 사용하여 딥 오브젝트 멤버의 값을 얻을 수 있습니다.

function objectGet(obj, path) { return new Function('_', 'return _.' + path)(obj); };

너의 경우에 고객의 경우,의 값을 가져올.part1.name부터에서someObject그냥 해 볼까요?다음 작업을 수행합니다.

objectGet(someObject, 'part1.name');

간단한 바이올린 데모를 소개합니다.https://jsfiddle.net/harishanchu/oq5esowf/

로다쉬가 달린 한 대의 정기선입니다.

const deep = { l1: { l2: { l3: "Hello" } } };
const prop = "l1.l2.l3";
const val = _.reduce(prop.split('.'), function(result, value) { return result ? result[value] : undefined; }, deep);
// val === "Hello"

아니면 더 좋은...

const val = _.get(deep, prop);

또는 ES6 버전(삭감 기능 포함)...

const val = prop.split('.').reduce((r, val) => { return r ? r[val] : undefined; }, deep);

플런커

내 생각엔 네가 이걸 원하는 것 같아.

var part1name = someObject.part1.name;
var part2quantity = someObject.part2.qty;
var part3name1 =  someObject.part3[0].name;

다음과 같은 것을 요구할 수 있습니다.

var part1name = someObject["part1"]["name"];
var part2quantity = someObject["part2"]["qty"];
var part3name1 =  someObject["part3"][0]["name"];

둘 다 효과가 있습니다.


아니면 이걸 원하실 수도 있어요

var partName = "part1";
var nameStr = "name";

var part1name = someObject[partName][nameStr];

마지막으로 이걸 요구할 수도 있어

var partName = "part1.name";

var partBits = partName.split(".");

var part1name = someObject[partBits[0]][partBits[1]];

대신 JS구문을 모방하려고 노력하면 각 구문 분석 한 다발을 보내기, 또는 단지 JS로 구문을 에뮬레이트하기 위해 많은 컴퓨팅 파싱에 소비하거나 이러한 답변(키와 이런 사실들은 뭉텅이 같지wrong/forget 것들(키를 가져 가질 것이다..S, 누군가에?음, 혹시 keys.sin의 배열 사용하나?).을 클릭합니다.

var part1name     = Object.get(someObject, ['part1', 'name']);
var part2quantity = Object.get(someObject, ['part2', 'qty']);
var part3name1    = Object.get(someObject, ['part3', 0, 'name']);

정답.

만약 대신 단일 문자열을 사용해야 하면서 단순히 그것 JSONify.대신 단일 문자열을 사용해야 할 경우 JSONify를 사용합니다.
이 메서드에 또 다른 향상이 뿌리 수준 개체 delete/set 수 있다는 것이다.이 방법의 또 다른 개선점은 루트 수준 개체를 삭제/설정할 수 있다는 것입니다.

function resolve(obj, path) {
    let root = obj = [obj];
    path = [0, ...path];
    while (path.length > 1)
        obj = obj[path.shift()];
    return [obj, path[0], root];
}
Object.get = (obj, path) => {
    let [parent, key] = resolve(obj, path);
    return parent[key];
};
Object.del = (obj, path) => {
    let [parent, key, root] = resolve(obj, path);
    delete parent[key];
    return root[0];
};
Object.set = (obj, path, value) => {
    let [parent, key, root] = resolve(obj, path);
    parent[key] = value;
    return root[0];
};

데모 다른 기능:기타기능 데모:
데먼스트레이션

bob = 위해서에.set(/.del(경로가 비어 있지 않은 경우(루트 개체를 포함)에는 필요하지 않습니다.
하기 위해 i i i i i i i i i i i i i i i i i i i i i 。stevebob == steve //true 후 첫 번째로.set(

2017년 이후에 이 질문을 방문하셔서 기억하기 쉬운 방법을 찾으시는 분들을 위해 JavaScript에서 네스트된 객체에 대한 자세한 블로그 게시글을 보내드립니다.

정의되지 않은 오류의 속성 'foo'를 읽을없습니다.

어레이 감소를 사용하여 중첩된 개체에 액세스

이 예를 들어 보겠습니다.

const user = {
    id: 101,
    email: 'jack@dev.com',
    personalInfo: {
        name: 'Jack',
        address: [{
            line1: 'westwish st',
            line2: 'washmasher',
            city: 'wallas',
            state: 'WX'
        }]
    }
}

네스트된 어레이에 액세스하려면 , 독자적인 어레이를 써, 사용율을 삭감할 수 있습니다.

const getNestedObject = (nestedObj, pathArr) => {
    return pathArr.reduce((obj, key) =>
        (obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}

// pass in your object structure as array elements
const name = getNestedObject(user, ['personalInfo', 'name']);

// to access nested array, just pass in array index as an element the path array.
const city = getNestedObject(user, ['personalInfo', 'address', 0, 'city']);
// this will return the city from the first address item.

이 모든 것을 가능하게 하는 최소한의 라이브러리 타입도 있습니다.

Typy를 사용하면 코드는 다음과 같습니다.

const city = t(user, 'personalInfo.address[0].city').safeObject;

면책사항:저는 이 패키지의 작성자입니다.

여기에서는 여러 가지 면에서 더 빠른 방법을 제시합니다.

옵션 1: ., [ 또는 ], ' 또는 '의 문자열을 분할하여 반대로 하여 빈 항목을 건너뜁니다.

function getValue(path, origin) {
    if (origin === void 0 || origin === null) origin = self ? self : this;
    if (typeof path !== 'string') path = '' + path;
    var parts = path.split(/\[|\]|\.|'|"/g).reverse(), name; // (why reverse? because it's usually faster to pop off the end of an array)
    while (parts.length) { name=parts.pop(); if (name) origin=origin[name]; }
    return origin;
}

2 것,즉 「2」(「2」)를 제외)eval): 낮은 수준의 문자 스캔(regex/split 등, 간단한 문자 스캔)참고: 이것은 인덱스에 대한 따옴표를 지원하지 않습니다.

function getValue(path, origin) {
    if (origin === void 0 || origin === null) origin = self ? self : this;
    if (typeof path !== 'string') path = '' + path;
    var c = '', pc, i = 0, n = path.length, name = '';
    if (n) while (i<=n) ((c = path[i++]) == '.' || c == '[' || c == ']' || c == void 0) ? (name?(origin = origin[name], name = ''):(pc=='.'||pc=='['||pc==']'&&c==']'?i=n+2:void 0),pc=c) : name += c;
    if (i==n+2) throw "Invalid path: "+path;
    return origin;
} // (around 1,000,000+/- ops/sec)

옵션 3: (신규: 옵션2를 확장하여 견적을 지원 - 다소 느리지만 여전히 빠름)

function getValue(path, origin) {
    if (origin === void 0 || origin === null) origin = self ? self : this;
    if (typeof path !== 'string') path = '' + path;
    var c, pc, i = 0, n = path.length, name = '', q;
    while (i<=n)
        ((c = path[i++]) == '.' || c == '[' || c == ']' || c == "'" || c == '"' || c == void 0) ? (c==q&&path[i]==']'?q='':q?name+=c:name?(origin?origin=origin[name]:i=n+2,name='') : (pc=='['&&(c=='"'||c=="'")?q=c:pc=='.'||pc=='['||pc==']'&&c==']'||pc=='"'||pc=="'"?i=n+2:void 0), pc=c) : name += c;
    if (i==n+2 || name) throw "Invalid path: "+path;
    return origin;
}

JSPerf: http://jsperf.com/ways-to-dereference-a-delimited-property-string/3

평가(...)(퍼포먼스에 관해서는)"는 여전히 최고입니다.속성 경로를 직접 관리하면 '평가'를 사용하는 데 문제가 없습니다(특히 속도가 필요한 경우)."전선을 통해" 부동산 경로를 끌어당기는 경우(회선 위에!?)lol:P) 그럼 안전을 위해 다른 것을 사용하세요.오직 바보만이 "평가"를 사용해야 하는 타당한 이유가 있기 때문에, "평가"를 전혀.또, 「더그 크록포드의 JSON 파서에 사용되고 있다.입력이 안전하다면 전혀 문제가 없습니다.올바른 작업에 적합한 도구를 사용하는 것이 좋습니다.

각도 JS

Speigg의 접근법은 매우 깔끔하고 깨끗하지만, Angular에 접속하는 솔루션을 찾다가 이 답변을 발견했습니다.문자열 경로별 JS $scope 속성 및 약간의 변경으로 다음과 같은 작업을 수행합니다.

$scope.resolve = function( path, obj ) {
    return path.split('.').reduce( function( prev, curr ) {
        return prev[curr];
    }, obj || this );
}

루트 컨트롤러에 이 함수를 배치하고 다음과 같은 하위 스코프를 사용합니다.

$scope.resolve( 'path.to.any.object.in.scope')

경로 구문 분석과 관련된 문제를 적절하게 감지하고 보고할 수 있는 솔루션을 원하는 경우 라이브러리 경로 값에 대한 자체 솔루션을 작성했습니다.

const {resolveValue} = require('path-value');

resolveValue(someObject, 'part1.name'); //=> Part 1
resolveValue(someObject, 'part2.qty'); //=> 50
resolveValue(someObject, 'part3.0.name'); //=> Part 3A

에는 ""를 사용합니다..0[0] 패널티가 되지만, '퍼포먼스 패널티'는 '퍼포먼스 패널티'가 추가되기 .0자바스크립트

단, 완전한 ES5 JavaScript 구문도 지원됩니다.먼저 토큰화만 하면 됩니다.

const {resolveValue, tokenizePath} = require('path-value');

const path = tokenizePath('part3[0].name'); //=> ['part3', '0', 'name']

resolveValue(someObject, path); //=> Part 3A
/**
 * Access a deep value inside a object 
 * Works by passing a path like "foo.bar", also works with nested arrays like "foo[0][1].baz"
 * @author Victor B. https://gist.github.com/victornpb/4c7882c1b9d36292308e
 * Unit tests: http://jsfiddle.net/Victornpb/0u1qygrh/
 */
function getDeepVal(obj, path) {
    if (typeof obj === "undefined" || obj === null) return;
    path = path.split(/[\.\[\]\"\']{1,2}/);
    for (var i = 0, l = path.length; i < l; i++) {
        if (path[i] === "") continue;
        obj = obj[path[i]];
        if (typeof obj === "undefined" || obj === null) return;
    }
    return obj;
}

사용 가능

getDeepVal(obj,'foo.bar')
getDeepVal(obj,'foo.1.bar')
getDeepVal(obj,'foo[0].baz')
getDeepVal(obj,'foo[1][2]')
getDeepVal(obj,"foo['bar'].baz")
getDeepVal(obj,"foo['bar']['baz']")
getDeepVal(obj,"foo.bar.0.baz[1]['2']['w'].aaa[\"f\"].bb")

문자열 경로로 모든 작업을 수행할 수 있는 패키지를 아직 찾지 못했기 때문에 insert(), get()(기본 반환), set() 및 remove() 작업을 지원하는 나만의 빠른 패키지를 작성하게 되었습니다.

도트 표기법, 대괄호, 숫자 인덱스, 문자열 번호 속성 및 키가 단어 이외의 문자와 함께 사용할 수 있습니다.사용법은 다음과 같습니다.

> var jsocrud = require('jsocrud');

...

// Get (Read) ---
> var obj = {
>     foo: [
>         {
>             'key w/ non-word chars': 'bar'
>         }
>     ]
> };
undefined

> jsocrud.get(obj, '.foo[0]["key w/ non-word chars"]');
'bar'

https://www.npmjs.com/package/jsocrud

https://github.com/vertical-knowledge/jsocrud

문자열 또는 배열 경로 중 하나를 허용하는 단순한 함수입니다.

function get(obj, path) {
  if(typeof path === 'string') path = path.split('.');

  if(path.length === 0) return obj;
  return get(obj[path[0]], path.slice(1));
}

const obj = {a: {b: {c: 'foo'}}};

console.log(get(obj, 'a.b.c')); //foo

또는

console.log(get(obj, ['a', 'b', 'c'])); //foo

게 있어요.npm모듈: https://github.com/erictrinh/safe-access

사용 예:

var access = require('safe-access');
access(very, 'nested.property.and.array[0]');

감소는 좋지만, 각각에 대해 아무도 사용하지 않는 것이 놀랍습니다.

function valueForKeyPath(obj, path){
        const keys = path.split('.');
        keys.forEach((key)=> obj = obj[key]);
        return obj;
    };

시험

리액트와 함께 온라인 샵을 개발하고 있습니다.복사된 상태 객체의 값을 변경하여 전송 시 원래 상태를 업데이트하려고 했습니다.위의 예들은 대부분 복사된 객체의 구조를 변형시키기 때문에 나에게는 효과가 없었다.딥 네스트된 오브젝트 속성의 값에 액세스하여 값을 변경하는 함수의 작업 예를 찾았습니다.https://lowrey.me/create-an-object-by-path-in-javascript-2/ 에는 다음과 같은 내용이 있습니다.

const createPath = (obj, path, value = null) => {
  path = typeof path === 'string' ? path.split('.') : path;
  let current = obj;
  while (path.length > 1) {
    const [head, ...tail] = path;
    path = tail;
    if (current[head] === undefined) {
      current[head] = {};
    }
    current = current[head];
  }
  current[path[0]] = value;
  return obj;
};

사용할 수 있습니다.ramda도서관.

학습ramda또, 불변의 오브젝트도 간단하게 조작할 수 있습니다.


var obj = {
  a:{
    b: {
      c:[100,101,{
        d: 1000
      }]
    }
  }
};


var lens = R.lensPath('a.b.c.2.d'.split('.'));
var result = R.view(lens, obj);


https://codepen.io/ghominejad/pen/BayJZOQ

알니탁의 대답에 근거합니다.

폴리필을 수표로 포장하여 기능을 한 번 줄였습니다.

if (Object.byPath === undefined) {
  Object.byPath = (obj, path) => path
    .replace(/\[(\w+)\]/g, '.$1')
    .replace(/^\./, '')
    .split(/\./g)
    .reduce((ref, key) => key in ref ? ref[key] : ref, obj)
}

const data = {
  foo: {
    bar: [{
      baz: 1
    }]
  }
}

console.log(Object.byPath(data, 'foo.bar[0].baz'))

이것은 로직을 3개의 다른 함수로 분할함으로써 단순화할 수 있습니다.

const isVal = a => a != null; // everything except undefined + null

const prop = prop => obj => {
    if (isVal(obj)) {
        const value = obj[prop];
        if (isVal(value)) return value;
        else return undefined;
    } else return undefined;
};

const path = paths => obj => {
    const pathList = typeof paths === 'string' ? paths.split('.') : paths;
    return pathList.reduce((value, key) => prop(key)(value), obj);
};

//usage:
const myObject = { foo: { bar: { baz: 'taco' } } };
const result = path('foo.bar')(myObject);
//results => { baz: 'taco' }

이 변형은 다음을 지원합니다.

  • 배열 또는 문자열 인수 전달
  • 상대하다undefined호출 및 실행 중 값
  • 각 기능을 독립적으로 테스트
  • 각 기능을 독립적으로 사용

DotObject = obj => new Proxy(obj, {
  get: function(o,k) {
    const m = k.match(/(.+?)\.(.+)/)
    return m ? this.get(o[m[1]], m[2]) : o[k]
  }
})

const test = DotObject({a: {b: {c: 'wow'}}})
console.log(test['a.b.c'])

코딩 시에 다른 네스트 키에 액세스 할 필요가 있는 경우(이러한 키에 대처하는 것은 간단함), 어레이 표기법액세일러를 사용할 수 있습니다.

var part1name = someObject['part1']['name'];
var part2quantity = someObject['part2']['qty'];
var part3name1 =  someObject['part3'][0]['name'];

이들은 도트 표기법액세서(accessor)와 동등하며 실행 시 다음과 같이 다를 수 있습니다.

var part = 'part1';
var property = 'name';

var part1name = someObject[part][property];

와 동등하다

var part1name = someObject['part1']['name'];

또는

var part1name = someObject.part1.name;

이 질문으로 해결됐으면 좋겠는데...

편집

오브젝트 값에 액세스하기 위한 xpath 쿼리의 일종에 문자열을 사용하지 않습니다.쿼리를 해석하고 값을 취득하기 위해 함수를 호출해야 하기 때문에 다른 경로를 따릅니다.

var part1name = function(){ return this.part1.name; }
var part2quantity = function() { return this['part2']['qty']; }
var part3name1 =  function() { return this.part3[0]['name'];}

// usage: part1name.apply(someObject);

또는 적용방법이 마음에 들지 않는 경우

var part1name = function(obj){ return obj.part1.name; }
var part2quantity = function(obj) { return obj['part2']['qty']; }
var part3name1 =  function(obj) { return obj.part3[0]['name'];}

// usage: part1name(someObject);

함수는 더 짧고 명확하며 인터프리터는 구문 오류 등을 체크합니다.

덧붙여서, 간단한 과제만으로도 적당한 시기에 할 수 있을 것 같습니다만…

최근에 같은 질문을 받고 https://npmjs.org/package/tea-properties를 성공적으로 사용했는데, 이 역시 마찬가지입니다.set네스트된 오브젝트/캐릭터:

입수:

var o = {
  prop: {
    arr: [
      {foo: 'bar'}
    ]
  }
};

var properties = require('tea-properties');
var value = properties.get(o, 'prop.arr[0].foo');

assert(value, 'bar'); // true

설정:

var o = {};

var properties = require('tea-properties');
properties.set(o, 'prop.arr[0].foo', 'bar');

assert(o.prop.arr[0].foo, 'bar'); // true

앞의 답변을 바탕으로 괄호도 다룰 수 있는 기능을 만들었습니다.하지만 갈라져서 안에 점이 없어요.

function get(obj, str) {
  return str.split(/\.|\[/g).map(function(crumb) {
    return crumb.replace(/\]$/, '').trim().replace(/^(["'])((?:(?!\1)[^\\]|\\.)*?)\1$/, (match, quote, str) => str.replace(/\\(\\)?/g, "$1"));
  }).reduce(function(obj, prop) {
    return obj ? obj[prop] : undefined;
  }, obj);
}

// (IE9+) Two steps

var pathString = "[0]['property'].others[3].next['final']";
var obj = [{
  property: {
    others: [1, 2, 3, {
      next: {
        final: "SUCCESS"
      }
    }]
  }
}];

// Turn string to path array
var pathArray = pathString
    .replace(/\[["']?([\w]+)["']?\]/g,".$1")
    .split(".")
    .splice(1);

// Add object prototype method
Object.prototype.path = function (path) {
  try {
    return [this].concat(path).reduce(function (f, l) {
      return f[l];
    });
  } catch (e) {
    console.error(e);
  }
};

// usage
console.log(obj.path(pathArray));
console.log(obj.path([0,"doesNotExist"]));

언급URL : https://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-and-arrays-by-string-path

반응형