2013-04-19 8 views
16

W Pythonie dla słownika d,Ekwiwalent Javascript z Pythona na dict.setdefault?

d.setdefault('key', value) 

zestawy d['key'] = value jeśli 'key' nie był w d, a inaczej pozostawia go jak to jest.

Czy jest to czysty, idiomatyczny sposób, aby zrobić to na obiekcie JavaScript, czy też wymaga on instrukcji if?

Odpowiedz

11

Jest to w zasadzie jak przy użyciu komunikatu if, ale krócej:

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

Albo

d.key = d.key || value; 

Aktualizacja: jak @bobtato zauważyć, jeżeli nieruchomość jest już ustawiony na wartość false byłoby go zastąpić to, więc lepszym sposobem byłoby:

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

Lub do zrób to jak zasugerował (właśnie wersję Shorthanded):

'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 } 
+2

Lepszym testem dla niezdefiniowanych w JavaScript jest 'typeof (a [key]) ===" undefined "' i to się nie powiedzie, jeśli chcesz, aby wartości 'null' były puste, co wymaga dodatkowego testu' a [ klucz] == null'. Ponieważ Javascript jest językiem prawdy, zarówno 'undefined' i' null' są fałszywe, a zatem prosty 'a [klucz] || (a [klucz] = wartość) 'jest wszystkim, co jest niezbędne do tego celu i jest dość powszechne w praktyce. –

+0

@ptomato tak, masz rację, sprawdź zaktualizowaną odpowiedź. – stackoverflowery

13

Nie używaj d.key || (d.key = value)!

Jeśli d.key już istnieje, ale ma wartość uznaną za "fałsz" (np. Zero lub NaN lub pusty ciąg), to konstrukcja nadpisze go z domyślną wartością, co prawdopodobnie jest błędne w ogólnym walizka.

Ściśle odpowiednikiem kodu Pythona będzie if (!('key' in d)) d.key = value. Jeśli chcesz uwzględnić null (lub inne wartości fałszerstwa) jako niezdefiniowane, potrzebujesz do tego dodatkowych testów. Ale powinieneś dokładnie przemyśleć, co jest i nie jest falsy w JavaScript; na przykład 0 jest fałszywy, ale "0" jest prawdziwy, mimo że 0 == "0" ...

+0

Powiedziałbym "Nie używaj go, jeśli wartość jest wartością logiczną". – roberkules

+0

Jednak to nie tylko booleans. 'd.key' jest wartością fałszu, jeśli jest to:' [", 0, fałsz, NaN, null, undefined]', ** lub ** jeśli tak naprawdę nie jest zdefiniowane, więc test może się nie powieść d jest używany do przechowywania łańcuchów, liczb, wartości logicznych lub obiektów. Istnieje nawet możliwość posiadania właściwości, która istnieje, ale zawiera wartość 'undefined' (ponieważ' d.key = undefined' to nie to samo, co 'delete d.key'). – bobtato

+0

Ale zależy to także od użycia. Jeśli budujesz funkcję setDefault, zgadzam się. Jeśli musisz ustawić właściwość niektórych opcji, które przekazałeś do funkcji, wiesz, jaki to jest typ i czy możesz go użyć w odpowiedni sposób. – roberkules

5

Nie jest to zalecane i nigdy nie jest dobrym pomysłem rozszerzanie wbudowanych klas. Zamiast tego, lepiej tworzyć własne implementacje wbudowanych klas, podobnie jak robi to biblioteka YUI (YArray, itp.). Ja jednak zamierzam zaprzeczać, bo ja często stwierdzają, że wdrażanie użytecznych skróty takie jak ten są korzyści do pisania czystego kodu w utrzymaniu:

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

więc zobaczymy go w akcji ...

var a = {}; 

a.setdefault('mylist', []).push(1); 
a.setdefault('mylist', []).push(2); 

console.log(a.mylist.toString()); 
    1,2 

Jak już wspomniano, nigdy nie warto używać thing = thing || defaultThing, ponieważ testuje tylko nierównomierną liczbę równą true lub thing == true. W przeciwieństwie do wpisanej równości: thing === true lub thing !== undefined. Więc jedynym sposobem, aby poprawnie kod setdefault w sposób inline byłoby wykorzystać ten fragment wszędzie:

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

Ale jak już mówiłem, to tylko dodaje uwędzić do kodu i jest podatny na błędy nabytych od „przed kopiowaniem i wklej "syndrom".

+0

Powinna to być poprawna odpowiedź na to pytanie –

+0

, która powiedziała, dodając metodę setdefault do KAŻDEGO obiektu jest dyskusyjna dobra praktyka –

3

Nic wbudowany, ale ta funkcja będzie zrobić:

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

Jeśli obj będzie zawierać tylko wartości non-falsy, obj[prop] || (obj[prop] = deflt) jest w porządku prosta alternatywa (ale deflt zastąpi nic falsy). Ma to tę dodatkową zaletę, że deflt zostanie oszacowany tylko wtedy, gdy będzie potrzebna jego wartość, więc może być to kosztowne wyrażenie.