Проверка существования вложенного ключа объекта JavaScript - PullRequest
553 голосов
/ 13 апреля 2010

Если у меня есть ссылка на объект:

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

но мне было интересно, есть ли лучший способ.

Ответы [ 53 ]

0 голосов
/ 21 февраля 2019

Вот небольшая вспомогательная функция, которую я использую, для меня она довольно проста и понятна. Надеюсь, это полезно для некоторых:).

static issetFromIndices(param, indices, throwException = false) {
    var temp = param;

    try {
        if (!param) {
            throw "Parameter is null.";
        }

        if(!Array.isArray(indices)) {
            throw "Indices parameter must be an array.";
        }

        for (var i = 0; i < indices.length; i++) {
            var index = indices[i];
            if (typeof temp[index] === "undefined") {
                throw "'" + index + "' index is undefined.";
            }


            temp = temp[index];
        }
    } catch (e) {
        if (throwException) {
            throw new Error(e);
        } else {
            return false;
        }
    }

    return temp;
}

var person = {
    hobbies: {
        guitar: {
            type: "electric"
        }
    }
};

var indices = ["hobbies", "guitar", "type"];
var throwException = true;

try {
    var hobbyGuitarType = issetFromIndices(person, indices, throwException);
    console.log("Yay, found index: " + hobbyGuitarType);
} catch(e) {
    console.log(e);
}
0 голосов
/ 19 июля 2012

Другое решение ES5:

function hasProperties(object, properties) {
    return !properties.some(function(property){
        if (!object.hasOwnProperty(property)) {
            return true;
        }
        object = object[property];
        return false;
    });
}
0 голосов
/ 19 февраля 2015
function isIn(string, object){
    var arr = string.split(".");
    var notFound = true;
    var length = arr.length;
    for (var i = 0; i < length; i++){
        var key = arr[i];
        if (!object.hasOwnProperty(key)){
            notFound = false;
            break;
        }
        if ((i + length) <= length){
            object = object[key];
        }
    }
    return notFound;
}
var musicCollection = {
    hasslehoff: {
        greatestHits : true
    }
};
console.log(isIn("hasslehoff.greatestHits", musicCollection));
console.log(isIn("hasslehoff.worseHits", musicCollection));

здесь моя версия на основе строк.

0 голосов
/ 27 октября 2010

Я автоматизировал процесс

if(isset(object,["prop1","prop2"])){
// YES!

}

function isset(object, props){
    var dump;
    try {
        for(var x in props){
            if(x == 0) {
                dump = object[props[x]];
                return;
            }
            dump = dump[props[x]];
        }
    } catch(e) {
        return false;
    }

    return true;
}
0 голосов
/ 05 сентября 2013

Другой вариант (близко к этот ответ ):

function resolve(root, path){
    try {
        return (new Function(
            'root', 'return root.' + path + ';'
        ))(root);
    } catch (e) {}
}

var tree = { level1: [{ key: 'value' }] };
resolve(tree, 'level1[0].key'); // "value"
resolve(tree, 'level1[1].key'); // undefined

Подробнее об этом: https://stackoverflow.com/a/18381564/1636522

0 голосов
/ 09 октября 2018

путь к объекту и путь можно разделить с помощью "."

function checkPathExist(obj, path) {
  var pathArray =path.split(".")
  for (var i of pathArray) {
    if (Reflect.get(obj, i)) {
      obj = obj[i];
		
    }else{
		return false;
    }
  }
	return true;
}

var test = {level1:{level2:{level3:'level3'}} };

console.log('level1.level2.level3 => ',checkPathExist(test, 'level1.level2.level3')); // true
console.log( 'level1.level2.foo => ',checkPathExist(test, 'level1.level2.foo')); // false
0 голосов
/ 19 января 2017

Я использую функцию следующим образом.

var a = {};
a.b = {};
a.b.c = {};
a.b.c.d = "abcdabcd";

function isDefined(objectChainString) {
    try {
        var properties = objectChainString.split('.');
        var currentLevel = properties[0];
        if (currentLevel in window) {
            var consolidatedLevel = window[currentLevel];
            for (var i in properties) {
                if (i == 0) {
                    continue;
                } else {
                    consolidatedLevel = consolidatedLevel[properties[i]];
                }
            }
            if (typeof consolidatedLevel != 'undefined') {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    } catch (e) {
        return false;
    }
}

// defined
console.log(checkUndefined("a.b.x.d"));
//undefined
console.log(checkUndefined("a.b.c.x"));
console.log(checkUndefined("a.b.x.d"));
console.log(checkUndefined("x.b.c.d"));
0 голосов
/ 05 марта 2019

В typeScript вы можете сделать что-то вроде этого:

 if (object.prop1 && object.prop1.prop2 && object.prop1.prop2.prop3) {
    const items = object.prop1.prop2.prop3
    console.log(items);
 }
0 голосов
/ 11 марта 2013

Мое решение, которое я использую долгое время (к сожалению, с использованием строки, не могу найти лучшего)

function get_if_exist(str){
    try{return eval(str)}
    catch(e){return undefined}
}

// way to use
if(get_if_exist('test.level1.level2.level3')) {
    alert(test.level1.level2.level3);
}

// or simply 
alert(get_if_exist('test.level1.level2.level3'));

edit: эта работа, только если объект "test" имеет глобальную область действия / диапазон. иначе вы должны сделать что-то вроде:

// i think it's the most beautiful code I have ever write :p
function get_if_exist(obj){
    return arguments.length==1 || (obj[arguments[1]] && get_if_exist.apply(this,[obj[arguments[1]]].concat([].slice.call(arguments,2))));
}

alert(get_if_exist(test,'level1','level2','level3'));

изменить окончательную версию, чтобы разрешить 2 метода вызова:

function get_if_exist(obj){
    var a=arguments, b=a.callee; // replace a.callee by the function name you choose because callee is depreceate, in this case : get_if_exist
    // version 1 calling the version 2
    if(a[1] && ~a[1].indexOf('.')) 
        return b.apply(this,[obj].concat(a[1].split('.')));
    // version 2
    return a.length==1 ? a[0] : (obj[a[1]] && b.apply(this,[obj[a[1]]].concat([].slice.call(a,2))));
}

// method 1
get_if_exist(test,'level1.level2.level3');


// method 2
get_if_exist(test,'level1','level2','level3');
0 голосов
/ 03 мая 2019

Для этого есть небольшая схема, но иногда она может быть ошеломляющей. Я предлагаю вам использовать его для двух или трех вложений одновременно.

if (!(foo.bar || {}).weep) return;
// Return if there isn't a 'foo.bar' or 'foo.bar.weep'.

Как я, возможно, забыл упомянуть, вы могли бы также расширить это. Ниже приведен пример проверки вложенного foo.bar.weep.woop, или он вернется, если ни один не доступен.

if (!((foo.bar || {}).weep || {}).woop) return;
// So, return if there isn't a 'foo.bar', 'foo.bar.weep', or 'foo.bar.weep.woop'.
// More than this would be overwhelming.
...