【问题标题】:In JavaScript, is there an easier way to check if a property of a property exists?在 JavaScript 中,是否有更简单的方法来检查属性的属性是否存在?
【发布时间】:2011-10-03 15:01:17
【问题描述】:

有没有一种简单的方法来原生地确定 JavaScript 中的对象中是否存在深层属性?例如,我需要访问这样的属性:

var myVal = appData.foo.bar.setting;

但有可能 foo、foo.bar 或 foo.bar.setting 尚未定义。在 Groovy 中,我们可以这样做:

def myVal = appData?.foo?.bar?.setting

在 JavaScript 中是否有类似的方法可以做到这一点,而无需编写自定义函数或嵌套 if 语句?我发现this answer 很有用,但希望有一种更优雅、更少自定义的方式。

【问题讨论】:

标签: javascript


【解决方案1】:

我觉得这很方便:

var myVal = (myVal=appData) && (myVal=myVal.foo) && (myVal=myVal.bar) && myVal.settings;

如果存在属性,将尝试序列的下一部分。

&& 之前的表达式计算结果为假时,将不检查表达式的下一部分。如果未定义myVal.appData.foo.bar.settings 中的任何一个,则myVal (undefined( 的值将计算为false

【讨论】:

  • 请注意,这种方法对于深度嵌套的变量非常有用。当变量由两个名字组成时,如foo.barmyVal = foo && foo.bar更方便。
  • 括号内的那些“子任务”没有理由。 JavaScript 返回序列最后一个表达式的实际值,否则返回false。它不会像其他具有类似短路运算符的语言那样将值强制为布尔值。
  • @Pointy:子分配是为了避免重复属性名称,以便整体代码长度为 O(N) 而不是 O(N^2)。我自己会尝试在长度开始重要时切换到自定义函数。
  • @Pointy var myVal = appData && foo && bar && settings 不会产生预期的结果。请参阅我之前的评论。
  • 不,但我认为尖的意思是:var myVal = appData && appData.foo && appData.foo.bar && appData.foo.bar.settings;。如果 var 名称不长,实际上我更喜欢这种方式。但如果它们很长,我更喜欢你的方式,Rob。不管怎样,我喜欢它。 +1
【解决方案2】:

抱歉,不太好:

var myVal = appData && appData.foo && appData.foo.bar && appData.foo.bar.setting;

另一种选择:

try {
    var myVal = appData.foo.bar.setting;
} catch (e) {
    var myVal = undefined;
}

.运算符并不是真正用于访问这样的对象。可能使用函数是个好主意。

【讨论】:

    【解决方案3】:

    我发现其他方法有点庞大。那么,以下方法的主要缺点是什么:

    // Pass the path as a string, parse it, and try to traverse the chain.
    Object.prototype.pathExists = function(path) {
        var members = path.split(".");
        var currentMember = this;
    
        for (var i = 0; i < members.length; i++) {
            // Here we need to take special care of possible method 
            // calls and arrays, but I am too lazy to write it down.
            if (currentMember.hasOwnProperty(members[i])) {
                currentMember = currentMember[members[i]];   
            } else {
                return false;
            }
        }
        return true;
    }
    

    基本上,我们在对象上定义一个方法(不一定),该方法获取嵌套对象的路径并返回存在确认,如appData.pathExists("foo.bar.setting");

    编辑: 检查object[prop] == undefined 在语义上不正确,因为即使定义了属性,尽管它的值为undefined,它也会返回false;这就是为什么我使用hasOwnProperty 来检查是否定义了属性。如果只需要获取值,这可能并不重要。

    【讨论】:

      【解决方案4】:

      如果,之后:

      var myVal = appData.foo && appData.foo.bar && appData.foo.bar.setting;
      

      myVal 不是undefined,它将保存appData.foo.bar.setting 的值。

      【讨论】:

        【解决方案5】:

        你可以试试这个

        var x = {y:{z:{a:'b'}}}
        x && x.y && x.y.z && x.y.z.a //returns 'b'
        

        这不如 groovy 表达式好,但它有效。遇到第一个未定义的变量后,评估停止。

        【讨论】:

          【解决方案6】:
          var product = ...,
              offering = (product||{}).offering,
              merchant = (offering||{}).merchant,
              merchantName = (merchant||{}).name;
          if (merchantName)
             displayMerchantName(merchantName);
          

          http://osteele.com/archives/2007/12/cheap-monads

          【讨论】:

            【解决方案7】:

            我刚刚做了这个,所以它可能无法完全正确地工作,我还包含了两个测试用例。

            function hasPropertyChain(o, properties) {
            
                var i = 0,
                    currentPropertyChain = o;
            
                if(!o) {
                    return false;
                }
            
                while(currentPropertyChain = currentPropertyChain[properties[i++]]);
            
                return i - 1 === properties.length;
            }
            
            
            alert(hasPropertyChain({a:{b:{c:'a'}}}, ['a','b','c'])); // true
            alert(hasPropertyChain({a:{b:{c:'a'}}}, ['a','b','c', 'd'])); // false
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2016-02-25
              • 1970-01-01
              • 2018-02-28
              • 1970-01-01
              • 1970-01-01
              • 2011-03-28
              • 1970-01-01
              相关资源
              最近更新 更多