【发布时间】:2013-04-13 00:39:36
【问题描述】:
在 Python 中,对于字典 d,
d.setdefault('key', value)
如果'key' 不在d 中,则设置d['key'] = value,否则保持原样。
是否有一种简洁、惯用的方式在 Javascript 对象上执行此操作,还是需要 if 语句?
【问题讨论】:
标签: javascript dictionary
在 Python 中,对于字典 d,
d.setdefault('key', value)
如果'key' 不在d 中,则设置d['key'] = value,否则保持原样。
是否有一种简洁、惯用的方式在 Javascript 对象上执行此操作,还是需要 if 语句?
【问题讨论】:
标签: javascript dictionary
这基本上就像使用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);
【讨论】:
a={}
key='3'
value = 2
a[key] = a[key] == undefined ? value : a[key]
## a = {'3': 2 }
【讨论】:
typeof(a[key]) === "undefined",如果您想将 null 值视为空,这将失败,这需要对 a[key] == null 进行额外测试。由于 Javascript 是一种真实的语言,undefined 和 null 都是错误的,因此一个简单的a[key] || (a[key] = value) 就足以实现这一目的,并且在实践中很常见。
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)”是错误的:如果一个元素存在但评估为false(false, 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 = undefined 与delete d.key 不同)。
不推荐,也不是增加内置类的好主意。相反,最好创建自己的内置类实现,这很像 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 绝不是一个好主意,因为它只测试true 或thing == true 的非类型相等性。与类型相等相反:thing === true 或 thing !== 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! */
但正如我已经说过的,这只会给您的代码增加臃肿,并且容易出现“复制粘贴”综合症导致的错误。
【讨论】:
没有什么内置的,但是这个函数可以做到:
function setDefault(obj, prop, deflt) {
return obj.hasOwnProperty(prop) ? obj[prop] : (obj[prop] = deflt);
}
如果obj 只包含非虚假值,obj[prop] || (obj[prop] = deflt) 是一个很好的简单替代方案(但deflt 将覆盖任何虚假值)。这还有一个额外的优势,deflt 只会在需要它的值时才被评估,所以它是一个昂贵的表达式是可以的。
【讨论】:
现在你也可以d.key ??= value
【讨论】:
undefined 或null 不允许合法地输入条目(这种情况很少发生),它就可以工作。并且,作为奖励,它是惰性的,因此不会对表达式 ??= expr 进行不必要的评估。当我只需要访问单个代码块中的属性时,我将使用它来替换 python 的defaultdict,例如(keyToList[key] ??= []).push.