【问题标题】:JavaScript, elegant way to check nested object properties for null/undefined [duplicate]JavaScript,检查嵌套对象属性是否为空/未定义的优雅方法[重复]
【发布时间】:2014-07-11 14:45:41
【问题描述】:

我不时遇到的一个“问题”是我有一个对象,例如user = {} 并在使用该应用程序的过程中填充。假设在某个地方,在 AJAX 调用或我这样做之后:

user.loc = {
    lat: 50,
    long: 9
}

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

if (user.loc.lat) {
    // do something
}

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

"Cannot read property 'lat' of null" - Dev Tools error

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

if (user.loc) {
    if (user.loc.lat) {
        // do something
    }
}

if (user.loc && user.loc.lat) {
    // do something
}

这不是很漂亮,而且我的对象越大,效果就越差 - 显然(想象一下 10 层嵌套)。 如果user.loc 也是undefinedif(user.loc.lat) 不只是返回 false,这让我感到很沮丧。

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

【问题讨论】:

  • 试试这个if(user && user.loc && user.loc.lat) {
  • 您可以使用typeof检查 null 和 undefined 的值
  • @AamirAfridi——尽管 OP 是这样写的,但测试应该停止在最后一个对象,而不是属性。例如如果user.loc.lat 存在但具有错误值(例如0),则测试将返回错误。 :-)

标签: javascript object javascript-objects


【解决方案1】:

您可以使用惰性and 组合检查:

if(user.loc && user.loc.lat) { ...

或者,您使用 CoffeeScript。并且 ES2020 有新的语法( Nullish coalescing Operator )。

user.loc?.lat?. '...'

它将检查loc 属性并防止空对象。

【讨论】:

  • 对不起,你们都回答得很快。您的第一种方法也是我想避免的情况。考虑到我有 5 到 15 层嵌套的巨大对象。
  • 这里没有太多选择。 (1) 手动或使用 CoffeeScript 进行属性检查,(2) try/catch。如果您有一个具有 15 级嵌套的对象,并且它的属性可能在任何级别都不存在,那么我认为您的应用程序有一些次优设计模式。
  • 这是一个例子。我想要一种方法来涵盖这种情况。我显然会避免 15 层嵌套,但如果一个旧的服务器端应用程序就是这样做的,我必须处理它怎么办?这就是为什么我想涵盖那个场景
  • .? 被称为optional chaining operator。空值合并运算符` (??) 与 OR 运算符 (||) 非常不同且更相似。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/….
【解决方案2】:

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

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

如果.loc 的值是false,则可以尝试

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

如果您有一个巨大的嵌套对象,请查看

Source.

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

更新: 试试lodash.get

【讨论】:

  • 对不起,你们都回答得很快。这也是我想避免的情况。考虑到我有 5 到 15 层嵌套的巨大对象。
  • 我讨厌人们不加评论就拒绝投票。
【解决方案3】:

你可以使用这样的实用函数:

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

用法:

 get(user, 'loc.lat')     // 50
 get(user, 'loc.foo.bar') // undefined

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

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')) ...

【讨论】:

  • 爱它!很好的解决方案。
  • get 方法的问题是它可能从链中的任何地方返回一个属性,它没有专门测试最后一个属性。
  • @RobG 怎么样?一旦它遇到一个未定义的,它就会一直通过并且结果是未定义的。
  • 我希望 lodash 能和这个函数。_.has 是最接近的,但不检查值。
  • 实际上,从头开始,确实如此!只需使用_.getstackoverflow.com/a/24046380/654708
【解决方案4】:

好吧,javascript 有 try-catch。根据您实际需要做的事情(即,如果它是 undefined,您的 else 语句会是什么样子),这可能就是您想要的。

示例:

try {
   user.loc.lat.doSomething();
} catch(error) {
   //report
}

【讨论】:

  • 啊当然。也是一个很好的答案,谢谢!
  • 我认为抛出异常而不是 if-else 不是一个好主意,如果您知道 var 可能未设置,我不认为这是一个异常,因此您应该处理它没有尝试捕获。 (当然你可以加入 else 子句)然后。
  • 我喜欢这个解决方案,用于处理有时会因条件句而变得难以阅读的简单内容。 @JonasStensved 指出不使用 try catch 是因为启动异常(我认为,在您编写 throw 之前,您不会启动它)但问题可能是块中出现其他问题,您将无法检测到它关于未来。
  • @pikilon 经验法则:不要使用异常进行流量控制。在您的情况下,某些事情确实出乎意料并且是异常,然后抛出。否则将其作为任何其他代码条件处理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-28
  • 1970-01-01
  • 2016-12-01
  • 2020-02-03
  • 1970-01-01
  • 1970-01-01
  • 2017-08-06
相关资源
最近更新 更多