JavaScript,检查嵌套对象属性是否为空/未定义的优雅方法

IT技术 javascript object javascript-objects
2021-03-01 23:18:55

我时不时遇到的一个“问题”是我有一个对象,例如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 级嵌套)。如果这样的话,if(user.loc.lat)它不仅会返回,这让我很不高兴falseuser.locundefined

检查此类情况的理想方法是什么?

4个回答

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

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')) ...
爱它!优秀的解决方案。
2021-04-20 23:18:55
get方法的问题在于它可能从链中的任何地方返回一个属性,它没有专门测试最后一个属性。
2021-04-25 23:18:55
实际上,从头开始,确实如此!只需使用_.get stackoverflow.com/a/24046380/654708
2021-05-06 23:18:55
我希望 lodash 会和一个功能。_.has是最接近的,但不检查值。
2021-05-07 23:18:55
@RobG 怎么样?一旦它遇到一个 undefined ,它就会一直通过并且结果是 undefined 。
2021-05-09 23:18:55

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

例子:

try {
   user.loc.lat.doSomething();
} catch(error) {
   //report
}
@pikilon 经验法则:不要使用异常进行流量控制。在您的情况下,确实有一些意外和异常,然后抛出。否则将其作为任何其他代码条件处理。
2021-04-23 23:18:55
我认为抛出异常而不是 if-else 不是一个好主意,如果您知道 var 可能未设置,我不认为这是一个异常,因此您应该在不抛出 try-catch 的情况下处理它。(当然,您可能会加入 else 子句)然后。
2021-04-25 23:18:55
啊当然。也很好回答,谢谢!
2021-05-06 23:18:55
我喜欢这种简单的东西的解决方案,这些东西有时会变得更难用条件阅读。@JonasStensved 指出不要使用 try catch 来解决这个问题,因为启动异常(throw我认为在你写之前你不会启动它)但问题可能是块中的其他问题,你将无法在未来检测到它.
2021-05-08 23:18:55

您可以使用 lazy 组合检查and

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

或者,您使用 CoffeeScript。ES2020 有新的语法(空合并运算符)。

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

这将运行loc财产检查并防止空对象。

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

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

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

如果.loc有valuefalse,您可以尝试

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

更新: 尝试lodash.get

对不起,你们都回答得很快。这也是我想避免的情况。考虑到我有 5 到 15 层嵌套的巨大对象。
2021-05-05 23:18:55
我讨厌人们不加评论就拒绝投票。
2021-05-07 23:18:55