JavaScript,优雅的方法来检查NULL/undefined的嵌套对象属性

Pro*_*mit 96 javascript object javascript-objects

一个"问题",我时不时地有一个对象,例如user = {},通过使用应用程序的过程,这将被填充.让我们说一下,在AJAX调用之后或者我这样做的事情:

user.loc = {
    lat: 50,
    long: 9
}
Run Code Online (Sandbox Code Playgroud)

在另一个地方,我想检查是否user.loc.lat存在.

if (user.loc.lat) {
    // do something
}
Run Code Online (Sandbox Code Playgroud)

如果它不存在,这将导致错误.如果user.loc.latundefined,user.loc当然也是undefined如此.

"Cannot read property 'lat' of null" - Dev Tools error
Run Code Online (Sandbox Code Playgroud)

这意味着我需要像这样检查:

if (user.loc) {
    if (user.loc.lat) {
        // do something
    }
}
Run Code Online (Sandbox Code Playgroud)

要么

if (user.loc && user.loc.lat) {
    // do something
}
Run Code Online (Sandbox Code Playgroud)

这不是很漂亮,我的对象越大越好 - 显然(想象10级嵌套).它种烧伤我,if(user.loc.lat)不只是返回false,如果user.locundefined也.

检查这种情况的理想方法是什么?

geo*_*org 129

您可以使用这样的实用程序函数:

get = function(obj, key) {
    return key.split(".").reduce(function(o, x) {
        return (typeof o == "undefined" || o === null) ? o : o[x];
    }, obj);
}
Run Code Online (Sandbox Code Playgroud)

用法:

 get(user, 'loc.lat')     // 50
 get(user, 'loc.foo.bar') // undefined
Run Code Online (Sandbox Code Playgroud)

或者,仅检查属性是否存在,而不检查其值:

has = function(obj, key) {
    return key.split(".").every(function(x) {
        if(typeof obj != "object" || obj === null || ! x in obj)
            return false;
        obj = obj[x];
        return true;
    });
}

if(has(user, 'loc.lat')) ...
Run Code Online (Sandbox Code Playgroud)

  • 实际上,刮擦它,它确实!只需使用`_.get` http://stackoverflow.com/a/24046380/654708 (7认同)
  • *get*方法的问题在于它可能从链中的任何位置返回属性,它不会专门测试最后一个属性. (4认同)
  • 爱它!优秀的解决方 (2认同)
  • @RobG怎么回事?一旦碰到一个不确定的东西,就一直传递下去,结果是不确定的。 (2认同)

Mar*_*oDS 19

好吧,javascript有try-catch.根据你实际需要做的事情(即你的else陈述是什么样子undefined),这可能是你想要的.

例:

try {
   user.loc.lat.doSomething();
} catch(error) {
   //report
}
Run Code Online (Sandbox Code Playgroud)

  • 我不认为抛出异常而不是if-else是个好主意,如果你知道var可能没有设置,我不认为是异常,因此你应该处理它而不抛出try-catch.(当然你可能会抛出else子句)然后. (6认同)

pun*_*und 10

您可以使用lazy组合检查and:

if(user.loc && user.loc.lat) { ...
Run Code Online (Sandbox Code Playgroud)

或者,您使用CoffeeScript并编写

user.loc?.lat ...
Run Code Online (Sandbox Code Playgroud)

它将运行对loc属性的检查并防止空对象.

  • `.?` 称为“可选链运算符”。空合并运算符 (`??`) 与 OR 运算符 (`||`) 非常不同,并且更相似。https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator#relationship_with_the_optional_chaining_operator_。 (3认同)
  • 抱歉,你们都回答得很快。您的第一种方法也是我要避免的情况。考虑到我有5到15个嵌套级别的巨大对象。 (2认同)

Aam*_*idi 6

试试这个 if(user && user.loc && user.loc.lat) {...}

您可以使用typeof检查null和undefined的值

如果.loc有价值false,你可以尝试

if(user && user.loc && typeof(user.loc)!=="undefined"){...}

如果你有一个巨大的嵌套对象而不是看看

来源.

function checkNested(obj /*, level1, level2, ... levelN*/) {
  var args = Array.prototype.slice.call(arguments),
      obj = args.shift();

  for (var i = 0; i < args.length; i++) {
    if (!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
Run Code Online (Sandbox Code Playgroud)

更新: 尝试lodash.get

  • 我讨厌人们投票而不添加评论. (5认同)