객체에 대한 참조가있는 경우 :
var test = {};
잠재적으로 (즉시는 아니지만) 중첩 된 객체를 가질 것입니다.
{level1: {level2: {level3: "level3"}}};
깊이 중첩 된 객체에 속성이 있는지 확인하는 가장 좋은 방법은 무엇입니까?
alert(test.level1);
수율 undefined
하지만,alert(test.level1.level2.level3);
실패합니다.
나는 현재 다음과 같은 일을하고있다 :
if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
alert(test.level1.level2.level3);
}
그러나 더 좋은 방법이 있는지 궁금합니다.
답변
TypeError
멤버 중 하나가 null
또는 undefined
이고 멤버 에 액세스하려고하면 예외가 발생 하기 때문에 원하지 않으면 단계별로 수행해야합니다 .
단순히 catch
예외를 수행하거나 다음과 같이 여러 레벨의 존재를 테스트하는 기능을 만들 수 있습니다 .
function checkNested(obj /*, level1, level2, ... levelN*/) {
var args = Array.prototype.slice.call(arguments, 1);
for (var i = 0; i < args.length; i++) {
if (!obj || !obj.hasOwnProperty(args[i])) {
return false;
}
obj = obj[args[i]];
}
return true;
}
var test = {level1:{level2:{level3:'level3'}} };
checkNested(test, 'level1', 'level2', 'level3'); // true
checkNested(test, 'level1', 'level2', 'foo'); // false
ES6 업데이트 :
다음은 ES6 기능 및 재귀를 사용하는 원래 기능의 짧은 버전입니다 ( 적절한 테일 호출 형식 임).
function checkNested(obj, level, ...rest) {
if (obj === undefined) return false
if (rest.length == 0 && obj.hasOwnProperty(level)) return true
return checkNested(obj[level], ...rest)
}
그러나 중첩 속성의 값을 가져 와서 존재 여부를 확인하려는 경우 간단한 한 줄 함수는 다음과 같습니다.
function getNested(obj, ...args) {
return args.reduce((obj, level) => obj && obj[level], obj)
}
const test = { level1:{ level2:{ level3:'level3'} } };
console.log(getNested(test, 'level1', 'level2', 'level3')); // 'level3'
console.log(getNested(test, 'level1', 'level2', 'level3', 'length')); // 6
console.log(getNested(test, 'level1', 'level2', 'foo')); // undefined
console.log(getNested(test, 'a', 'b')); // undefined
위의 함수를 사용하면 중첩 속성 값을 얻을 수 있습니다 undefined
. 그렇지 않으면를 반환 합니다.
2019-10-17 업데이트 :
옵션 체인 제안 온 3 단계에 도달 ECMAScript를위원회 과정 이 허용됩니다 당신 토큰을 사용하여 안전하게 액세스 중첩 특성에 ?.
새로운 옵션 체인 운영자 :
const value = obj?.level1?.level2?.level3
액세스 된 레벨 중 하나가 null
있거나 undefined
식 undefined
자체 가 해결 되는 경우.
이 제안을 통해 메소드 호출을 안전하게 처리 할 수 있습니다.
obj?.level1?.method();
상기 식을 생성 할 undefined
경우 obj
, obj.level1
또는 obj.level1.method
이다 null
또는 undefined
그렇지 않으면 그 함수를 호출한다.
옵션 체인 플러그인을 사용하여 Babel에서이 기능을 사용할 수 있습니다 .
이후 바벨 7.8.0 , ES2020은 기본적으로 지원됩니다
Babel REPL 에서이 예 를 확인하십시오 .
??UPDATE : 2019 년 12 월 ??
옵션 체인 제안은 마침내 TC39위원회의 2019 년 12 월 회의에서 4 단계에 도달했습니다 . 이는이 기능이 ECMAScript 2020 표준의 일부라는 것을 의미합니다 .
답변
Oliver Steele에서 얻은 패턴은 다음과 같습니다 .
var level3 = (((test || {}).level1 || {}).level2 || {}).level3;
alert( level3 );
사실 전체 기사는 자바 스크립트에서 어떻게 할 수 있는지에 대한 토론입니다. 그는 위의 구문을 사용하기로 결정했습니다 (이것에 익숙해지면 읽기가 어렵지 않습니다).
답변
최신 정보
lodash 가 _.get
모든 중첩 속성 요구 사항을 추가 한 것 같습니다.
_.get(countries, 'greece.sparta.playwright')
이전 답변
lodash 사용자는 이 문제를 완화 하는 몇 가지 방법 이있는 lodash.contrib 를 즐길 수 있습니다 .
getPath
서명: _.getPath(obj:Object, ks:String|Array)
제공된 키로 설명 된 경로를 기반으로 중첩 된 개체의 깊이에있는 값을 가져옵니다. 키는 배열 또는 점으로 구분 된 문자열로 제공 될 수 있습니다. undefined
경로에 도달 할 수없는 경우를 반환 합니다.
var countries = {
greece: {
athens: {
playwright: "Sophocles"
}
}
}
};
_.getPath(countries, "greece.athens.playwright");
// => "Sophocles"
_.getPath(countries, "greece.sparta.playwright");
// => undefined
_.getPath(countries, ["greece", "athens", "playwright"]);
// => "Sophocles"
_.getPath(countries, ["greece", "sparta", "playwright"]);
// => undefined
답변
내가 수행 한 성능 테스트를 (당신에게 감사 cdMinix을 아래에 나열된 결과이 질문에 제안 된 아이디어에 대한 lodash를 추가).
고지 사항 # 1 문자열을 참조로 바꾸는 것은 불필요한 메타 프로그래밍이며 피하는 것이 가장 좋습니다. 시작하기 위해 참조를 잃어 버리지 마십시오. 이 질문에서 비슷한 질문에 대한 자세한 내용을 읽으십시오 .
고지 사항 # 2 여기서는 밀리 초당 수백만 건의 작업에 대해 이야기하고 있습니다. 이들 중 어느 것도 대부분의 사용 사례에서 큰 차이를 만들 가능성은 거의 없습니다. 각각의 한계를 아는 것이 가장 적합한 것을 선택하십시오. 나를 위해 나는
reduce
편의 가 아닌 것과 함께 갈 것입니다 .
Object Wrap (Oliver Steele 제공) – 34 % – 가장 빠름
var r1 = (((test || {}).level1 || {}).level2 || {}).level3;
var r2 = (((test || {}).level1 || {}).level2 || {}).foo;
독창적 인 솔루션 (문제의 제안) – 45 %
var r1 = test.level1 && test.level1.level2 && test.level1.level2.level3;
var r2 = test.level1 && test.level1.level2 && test.level1.level2.foo;
checkNested – 50 %
function checkNested(obj) {
for (var i = 1; i < arguments.length; i++) {
if (!obj.hasOwnProperty(arguments[i])) {
return false;
}
obj = obj[arguments[i]];
}
return true;
}
get_if_exist – 52 %
function get_if_exist(str) {
try { return eval(str) }
catch(e) { return undefined }
}
유효한 체인 – 54 %
function validChain( object, ...keys ) {
return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}
objHasKeys – 63 %
function objHasKeys(obj, keys) {
var next = keys.shift();
return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}
nestedPropertyExists – 69 %
function nestedPropertyExists(obj, props) {
var prop = props.shift();
return prop === undefined ? true : obj.hasOwnProperty(prop) ? nestedPropertyExists(obj[prop], props) : false;
}
_.get – 72 %
가장 깊은 – 86 %
function deeptest(target, s){
s= s.split('.')
var obj= target[s.shift()];
while(obj && s.length) obj= obj[s.shift()];
return obj;
}
슬픈 광대 – 100 % – 가장 느림
var o = function(obj) { return obj || {} };
var r1 = o(o(o(o(test).level1).level2).level3);
var r2 = o(o(o(o(test).level1).level2).foo);
답변
문자열처럼 이름을 처리하면 깊이에 상관없이 객체 속성을 읽을 수 있습니다 't.level1.level2.level3'
.
window.t={level1:{level2:{level3: 'level3'}}};
function deeptest(s){
s= s.split('.')
var obj= window[s.shift()];
while(obj && s.length) obj= obj[s.shift()];
return obj;
}
alert(deeptest('t.level1.level2.level3') || 'Undefined');
undefined
세그먼트 중 하나 가 이면 반환 됩니다 undefined
.
답변
var a;
a = {
b: {
c: 'd'
}
};
function isset (fn) {
var value;
try {
value = fn();
} catch (e) {
value = undefined;
} finally {
return value !== undefined;
}
};
// ES5
console.log(
isset(function () { return a.b.c; }),
isset(function () { return a.b.c.d.e.f; })
);
당신이 ES6 환경에서 코딩 (또는 사용하는 경우 6to5를 ) 다음은 이용 취할 수 화살표 기능 구문 :
// ES6 using the arrow function
console.log(
isset(() => a.b.c),
isset(() => a.b.c.d.e.f)
);
성능과 관련하여 사용에 대한 성능 불이익은 없습니다 try..catch
속성을 설정 한 경우 블록 하면 . 속성이 설정되어 있지 않으면 성능에 영향을 미칩니다.
단순히 다음을 사용하십시오 _.has
.
var object = { 'a': { 'b': { 'c': 3 } } };
_.has(object, 'a');
// → true
_.has(object, 'a.b.c');
// → true
_.has(object, ['a', 'b', 'c']);
// → true
답변
어때?
try {
alert(test.level1.level2.level3)
} catch(e) {
...whatever
}
