【问题标题】:How do I traverse a JavaScript object and check for nulls?如何遍历 JavaScript 对象并检查空值?
【发布时间】:2012-09-22 17:25:13
【问题描述】:

假设我有一个 JavaScript 对象,例如:

var obj = {};
obj.computers = {};
obj.computers.favorite = "Commodore 64";
obj.computers.popular = "Apple";

现在,我可以轻松地检查 null,例如:

if(obj != 'undefined' && obj != null) {
    if(obj.computers != 'undefined' && obj.computers != null)) {
        .....

如您所见,如果我需要查看obj.computers.favorite 是否已设置,我必须在其中真正嵌套一些条件逻辑。我们的一些对象有 3、4、5 层深。

这是我希望能够做到的:

var fav = obj.computers.favorite || 'Unknown';

但我意识到我需要用某种方法来包装它。比如:

var fav = getValueOrDefault(obj.computers.favorite, 'Unknown');

建议表示赞赏。

谢谢

编辑

我对“未定义”的检查实际上并不是我使用的。当我问这个问题时,它只是从我的脑海中浮现出来。哈哈

但我想知道,我是否可以只包装一个 try/catch 并在异常时抛出默认值?

function(obj, default) {
    try {
        if(obj != null) {
            return obj;
        } else {
            return default;
        }
    } catch(ex) {
        return default;
    }
}

另外,感谢 Shusi 指出多余的变量。

【问题讨论】:

  • obj != 'undefined' && obj != null 不正确,因为要获得字符串值 'undefined',您需要 typeof。这是一个常见的错误。但无论哪种方式,它都是不必要的冗长。只需执行obj != null,它会同时测试undefined
  • getValueOrDefault(obj.computers.favorite, 'Unknown') 如果 obj.computers 未定义,则会抛出异常。您必须将其包装在一个字符串中并进行增量对象解析。
  • @saml 完全正确。这是我试图避免的。我们的 JS 对象有时会非常深入。我想我可以做一个 try/catch 并在异常时返回默认值?
  • 可选链是你想要的stackoverflow.com/a/60845999/2100372

标签: javascript isnull


【解决方案1】:

optional chaining operator 是一种更新的处理方式:

let favorite = obj?.computers?.favorite;

将此与nullish coalescing operator 结合使用,您可以精确地完成最初的要求:

let favorite = obj?.computers?.favorite ?? 'Unknown';

请注意,这些运算符都没有得到普遍支持。

【讨论】:

    【解决方案2】:

    您也可以使用 JavaScript ES5 reduce 函数来做到这一点:

    function get(root, member) {
        return member.split('.').reduce((acc, value) => {
            return (acc && typeof acc[value] !== 'undefined') ? acc[value] : undefined
        }, root);
    }
    

    它从成员字符串中创建一个数组,然后随着成员的减少,累加器在对象内逐步遍历。

    你可以像这样使用它,即使是数组:

    let obj = {
        computers : {
            favorite : "Commodore 64",
            popular : "Apple",
            list: [
                {
                    sn : "TDGE52343FD76",
                    price: "9867.99",
                    options: {
                        fanless: true
                    }
                }
            ]
        }
    }
    
    get(obj, 'computers.popular');
    // => "Apple"
    get(obj, 'computers.list.0.sn');
    // => "TDGE52343FD76"
    get(obj, 'computers.list.0.options.fanless');
    // => true
    get(obj, 'computers.list.0.options.runsWithoutEletricity');
    // => undefined
    get(obj, 'computers.list.0.options.runsWithoutEletricity') || "too bad..." ;
    // => "too bad..."
    

    safely traverse js object有一个codepen

    【讨论】:

      【解决方案3】:

      我写这篇文章是为了帮助您处理您的一个问题:“我需要查看是否设置了 obj.computers.favorite”。

      Object.prototype.isset = function (/* string */ full_path)
      {
          var props = full_path.split('.');
          var self = this; /* note that self is usually the window object */
      
          for (var ii = 0; ii < props.length; ++ii)
          {
              var prop = props[ii];
              var hasMoreComing = ii < props.length - 1 ? true : false;
      
              if (self[prop] !== null && typeof self[prop] === 'object' && hasMoreComing)
              {
                  self = self[prop];
                  continue;   // Move up one level.
              }
              else if (hasMoreComing)
                  return false;    // ..because user queries a subproperty of a value type
      
              return self.hasOwnProperty(prop);
          }
      };
      

      测试代码:

      var test = {};
      
      test.kuk = {};
      console.log( test.isset('kuk') );  // Prints true.
      
      test.kuk.fitta = {};
      console.log( test.isset('kuk.fitta') ); // Prints true.
      
      test.kuk.fitta = null;
      console.log( test.isset('kuk.fitta') ); // Prints true.
      
      test.kuk.fitta = undefined;
      console.log( test.isset('kuk.fitta') );  // Prints true
      
      delete test.kuk.fitta;
      console.log( test.isset('kuk.fitta') );  // Prints false
      
      test.kuk.fitta = 123;
      console.log( test.isset('kuk.fitta.doesnt.exist') );  // Prints false
      

      【讨论】:

      • 这不像 PHP isset 那样工作,因为它为 null 和 undefined 返回 true。
      【解决方案4】:

      您可以使用 helper 函数来完成。如果我正确理解了您的问题,您的对象可能有任意深度对象,并且您希望访问这些任意嵌套属性而不会弄乱您的代码。我构建了一个Nested 函数,它允许您get() 任意属性,如果它们被设置,或者如果它们没有被设置为默认值。

      var Nested = function() {};
      // prop is a dot-separated path like "foo.bar.baz"
      Nested.prototype.get = function(prop, _default) {
          var current = this;
          $.each(prop.split("."), function(i, e) {
              current = current[e] || undefined;
              if (current == undefined)
                  return false;
          });
          return current || _default;
      }
      

      你可以这样写代码

      var fav = obj.get("computers.favourite", "Linux");
      // this emulates
      var fav = obj.computers.favourite || "Linux"; // throws error
      

      如您所见,打字并没有那么多。当然,它不像 常规 Javascript...Here is the fiddle.

      【讨论】:

      • err,您需要将 var 声明更改为 var current = this; 和代码 current = current[e] || undefined;。小提琴就会正常工作。
      • 你应该提到你的答案需要 jquery。
      【解决方案5】:

      以下函数将字符串作为参数,如果存在则返回对象

       function getValueOrDefault(str , obj, deflt){
          var a = str.split("."); o = obj;
          for(var i =0; i < a.length; i++){
               o = obj[a[i]];
               if(!o){
                 return deflt;
               }
          }
            return o;
      }
      
      var obj = {};
      obj.computers = {};
      obj.computers.favorite = "Commodore 64";
      obj.computers.popular = "Apple";
      getValueOrDefault('computers.favorite', obj, 'Unknown');
      

      注意:在将属性分配给对象时,您不能使用 var,例如。 var obj.computers.favorite 是语法错误。

      【讨论】:

      • 我认为您可以交换 objdeflt 参数并更改 o = obj || window。所以你可以写getValueOrDefault('obj.computers.favorite', 'unknown')
      • 是的,你是对的。但这个解决方案更具体地针对上述问题。
      【解决方案6】:

      不幸的是,没有一种超级简单的方法可以解决这个问题,但您不需要同时检查 null 和 undefined。因为 null 和 undefined 都是假的,你可以这样做:

      if (obj && obj.computers) {
        var fav = obj.computers.favorite || 'unknown';
      }
      

      它实际上并不能解决你的抱怨是什么,但它没有你想象的那么痛苦。

      【讨论】:

        【解决方案7】:

        你真的会写:

        (obj && obj.computers && obj.computers.favorite) || 'Unknown'
        

        【讨论】:

        • +1,但请参阅我对通用解决方案的回答,该解决方案不会使代码与许多 ands 混淆,并且如果 OP 多次使用此模式会更有用。
        猜你喜欢
        • 1970-01-01
        • 2021-05-08
        • 2013-01-01
        • 1970-01-01
        • 2017-08-30
        • 2021-10-05
        • 2013-04-20
        • 2017-12-17
        • 1970-01-01
        相关资源
        最近更新 更多