Проверка существования вложенного ключа объекта JavaScript

562
задан Bergi 23 June 2019 в 12:41
поделиться

5 ответов

Вы должны делать это шаг за шагом, если не хотите 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.

380
ответ дан 22 November 2019 в 21:58
поделиться

Вы можете читать свойство объекта на любой глубине, если вы обращаетесь с именем как со строкой: '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.

43
ответ дан 22 November 2019 в 21:58
поделиться

как насчет

try {
   alert(test.level1.level2.level3)
} catch(e) {
 ...whatever

}
22
ответ дан 22 November 2019 в 21:58
поделиться
/**
 * @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
0
ответ дан 22 November 2019 в 21:58
поделиться

Довольно много ответов, но все еще: почему не более простой?

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, которое дало мне эту идею.

0
ответ дан 22 November 2019 в 21:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: