Вы должны делать это шаг за шагом, если не хотите TypeError
, потому что если один из членов - null
или undefined
, и вы пытаетесь получить доступ к члену, возникает исключение.
Вы можете просто перехватить
исключение или создать функцию для проверки существования нескольких уровней, примерно так:
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
ОБНОВЛЕНИЕ 2019-05-16:
Вот более короткий версия, использующая функции 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)
}
ОБНОВЛЕНИЕ 2019-10-17:
Предложение по необязательной цепочке достигло этапа 3 на процесс комитета ECMAScript , это позволит вам безопасно получить доступ к глубоко вложенным свойствам с помощью токена ?.
, новый необязательный оператор цепочки :
const value = obj?.level1?.level2?.level3
Если какой-либо из доступных уровней имеет значение null
или undefined
, выражение будет преобразовано в undefined
сам по себе.
Предложение также позволяет безопасно обрабатывать вызовы методов:
obj?.level1?.method();
Вышеупомянутое выражение даст undefined
if obj
, obj.level1
или obj.level1.method
имеют значение null
или undefined
, иначе он вызовет функцию.
Вы можете начать играть с этой функцией в Babel, используя дополнительный плагин связывания .
Проверьте этот пример на Babel REPL.
Вы можете читать свойство объекта на любой глубине, если вы обращаетесь с именем как со строкой: '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
.
как насчет
try {
alert(test.level1.level2.level3)
} catch(e) {
...whatever
}
/**
* @method getValue
* @description simplifies checking for existance and getting a deeply nested value within a ceratin context
* @argument {string} s string representation of the full path to the requested property
* @argument {object} context optional - the context to check defaults to window
* @returns the value if valid and set, returns undefined if invalid / not available etc.
*/
var getValue = function( s, context ){
var fn = function(){
try{
return eval(s);
}catch(e){
return undefined;
}
}
return fn.call(context||window,s);
}
и использование:
if( getValue('a[0].b[0].b[0].d') == 2 ) // true
Довольно много ответов, но все еще: почему не более простой?
es5 версия получения значения была бы:
function value(obj, keys) {
if (obj === undefined) return obj;
if (keys.length === 1 && obj.hasOwnProperty(keys[0])) return obj[keys[0]];
return value(obj[keys.shift()], keys);
}
if (value(test, ['level1', 'level2', 'level3'])) {
// do something
}
Вы могли также использовать его с value(config, ['applet', i, 'height']) || 42
Кредиты к CMS для его решения ES6, которое дало мне эту идею.