【问题标题】:Javascript equivalent of Python's dict.setdefault?Javascript 相当于 Python 的 dict.setdefault?
【发布时间】:2013-04-13 00:39:36
【问题描述】:

在 Python 中,对于字典 d

d.setdefault('key', value)

如果'key' 不在d 中,则设置d['key'] = value,否则保持原样。

是否有一种简洁、惯用的方式在 Javascript 对象上执行此操作,还是需要 if 语句?

【问题讨论】:

    标签: javascript dictionary


    【解决方案1】:

    这基本上就像使用if 语句,但更短:

    d.key || (d.key = value);
    

    或者

    d.key = d.key || value;
    

    更新:正如@bobtato 所说,如果属性已经设置为值false,它将覆盖它,所以更好的方法是:

    !d.key && d.key !== false && (d.key = value);
    

    或者,按照他的建议去做(只是简写版本):

    'key' in d || (d.key = value);
    
    // including overwriting null values:
    
    ('key' in d && d.key !== null) || (d.key = value);
    

    【讨论】:

      【解决方案2】:
      a={}
      key='3'
      value = 2
      a[key] = a[key] == undefined ? value : a[key]
      
      ## a = {'3': 2 }
      

      【讨论】:

      • 对 Javascript 中未定义的更好测试是 typeof(a[key]) === "undefined",如果您想将 null 值视为空,这将失败,这需要对 a[key] == null 进行额外测试。由于 Javascript 是一种真实的语言,undefinednull 都是错误的,因此一个简单的a[key] || (a[key] = value) 就足以实现这一目的,并且在实践中很常见。
      【解决方案3】:
      if (!('key' in d)) d.key = value;
      

      'key' in d || (d.key = value);
      

      (最后一个使用the short-circuit behavior of conditional expressions。)


      另一个答案中建议的“d.key || (d.key = value)”是错误的:如果一个元素存在但评估为falsefalse, null, 0, -0, "", undefined, NaN),它将被静默覆盖。

      • 虽然这可能是有意为之,但很可能并非针对上述所有情况。因此,在这种情况下,请分别检查值:

        if (!('key' in d) || d.key === null) d.key = value;
        

      【讨论】:

      • 我会说“如果值为布尔值,请不要使用它”。
      • 它不仅仅是布尔值。 d.key 如果它是以下任何一种,则评估为 false:["", 0, false, NaN, null, undefined],如果它实际上没有定义,则 ,因此如果 d 用于存储字符串、数字、布尔值或对象。甚至可以拥有一个存在但拥有值undefined 的属性(因为d.key = undefineddelete d.key 不同)。
      • 但这也取决于使用情况。如果你正在构建一个 setDefault 函数,我同意。如果您只需要设置传递给函数的某些选项的属性,您就知道它是什么类型并且可以以适当的方式使用它。
      【解决方案4】:

      不推荐,也不是增加内置类的好主意。相反,最好创建自己的内置类实现,这很像 YUI 库(YArray 等)。但是,我要反驳这一点,因为我经常发现像这样实现有用的捷径对于编写干净的可维护代码是有好处的:

      if (undefined === Object.prototype.setdefault) {
          Object.prototype.setdefault = function(key, def) {
              if (! this.hasOwnProperty(key)) {
                  this[key] = def;
              }
              return this[key];
          };
      }
      

      让我们来看看它的实际效果......

      var a = {};
      
      a.setdefault('mylist', []).push(1);
      a.setdefault('mylist', []).push(2);
      
      console.log(a.mylist.toString());
          1,2
      

      正如已经指出的那样,使用thing = thing || defaultThing 绝不是一个好主意,因为它只测试truething == true 的非类型相等性。与类型相等相反:thing === truething !== undefined。因此,以内联方式正确编码 setdefault 的唯一方法是在任何地方使用这个 sn-p:

      /* null == thing is equivalent to... */
      if (undefined !== thing && null !== thing) {
          thing = defaultThing;
      }
      /* ...but it's not explicit and linters don't like it! */
      

      但正如我已经说过的,这只会给您的代码增加臃肿,并且容易出现“复制粘贴”综合症导致的错误。

      【讨论】:

      • 这应该是这个问题的正确答案
      • 也就是说,向每个对象添加 setdefault 方法是值得商榷的好习惯
      【解决方案5】:

      没有什么内置的,但是这个函数可以做到:

      function setDefault(obj, prop, deflt) {
        return obj.hasOwnProperty(prop) ? obj[prop] : (obj[prop] = deflt);
      }
      

      如果obj 只包含非虚假值,obj[prop] || (obj[prop] = deflt) 是一个很好的简单替代方案(但deflt 将覆盖任何虚假值)。这还有一个额外的优势,deflt 只会在需要它的值时才被评估,所以它是一个昂贵的表达式是可以的。

      【讨论】:

        【解决方案6】:

        现在你也可以d.key ??= value

        【讨论】:

        • 太棒了!太感谢了。可能需要添加一个警告,只要undefinednull 不允许合法地输入条目(这种情况很少发生),它就可以工作。并且,作为奖励,它是惰性的,因此不会对表达式 ??= expr 进行不必要的评估。当我只需要访问单个代码块中的属性时,我将使用它来替换 python 的defaultdict,例如(keyToList[key] ??= []).push.
        猜你喜欢
        • 2010-09-07
        • 1970-01-01
        • 1970-01-01
        • 2011-07-28
        • 2017-06-25
        • 1970-01-01
        • 2017-01-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多