Javascript эквивалент Python dict.setdefault?

В Python для словаря d,

d.setdefault('key', value)

устанавливает d['key'] = value, если 'key' не находится в d, и в противном случае оставляет его как есть.

Есть ли чистый, идиоматический способ сделать это на объекте Javascript или требуется инструкция if?

Ответы

Ответ 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

Не используйте d.key || (d.key = value)!

Если d.key уже существует, но имеет значение, считающееся "ложным" (например, ноль или NaN или пустую строку), эта конструкция перезапишет его значением по умолчанию, которое, вероятно, будет неправильным в общем случае.

Строго эквивалент кода Python будет if (!('key' in d)) d.key = value. Если вы хотите рассмотреть null (или другие значения фальши) как undefined, для этого вам потребуются дополнительные тесты. Но вы должны тщательно подумать о том, что есть и не является ложным в JavaScript; например 0 является ложным, но "0" истинно, хотя 0 == "0"...

Ответ 3

Не рекомендуется и никогда не рекомендуется добавлять встроенные классы. Вместо этого лучше создать собственные реализации встроенных классов, что очень похоже на библиотеку 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 встроенным способом - использовать этот фрагмент повсюду:

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

Но, как я уже сказал, это просто добавляет вздутие к вашему коду и подвержено ошибкам, полученным от синдрома "копирование и вставка".

Ответ 4

Нет ничего встроенного, но эта функция будет делать это:

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

Если obj будет содержать только фальшивые значения, obj[prop] || (obj[prop] = deflt) является простой простой альтернативой (но deflt будет отменять что-либо ложное). Это имеет дополнительное преимущество, что deflt будет оцениваться только тогда, когда требуется его значение, поэтому для него это будет дорогостоящим выражением.

Ответ 5

a={}
key='3'
value = 2
a[key] = a[key] == undefined ? value : a[key]

## a = {'3': 2 }