JavaScript nesne niteliklerinin varsayılan değerini ayarlayın


83

Bir javascript nesnesinin varsayılan niteliğini şu şekilde ayarlamanın bir yolu var mı:

var emptyObj = {};
// do some magic
emptyObj.nonExistingAttribute // => defaultValue

IE göz ardı edilebilir, Chrome Frame beni bu baş ağrısından kurtardı.


Var olmayan HER öznitelik mi yoksa sadece BİLİNEN bir öznitelik adı mı?
js1568

Yanıtlar:


120

Birkaç yıl önce soruyu sorduğumdan beri işler güzel bir şekilde ilerledi.

Proxy'ler ES6'nın parçasıdır. Aşağıdaki örnek Chrome, Firefox, Safari ve Edge'de çalışır :

var handler = {
  get: function(target, name) {
    return target.hasOwnProperty(name) ? target[name] : 42;
  }
};

var p = new Proxy({}, handler);

p.answerToTheUltimateQuestionOfLife; //=> 42

Mozilla'nın Proxy'ler hakkındaki belgelerinde daha fazlasını okuyun .


Internet Explorer'ı ( Edge'den önce) desteklemeyi planlıyorsanız, şansınız kalmadı : caniuse.com/#search=proxy Ayrıca, polyfill github.com/tvcutsem/harmony-reflect IE'yi desteklemiyor
Tiagojdferreira

21
Tebrikler, Phoenix'i kazandınız (Altın Rozet: en popüler cevabın oy sayısını en az iki katına çıkaran bir yanıtla en az bir yıl sonra kendi sorularınızdan birini yanıtladı)
Ziggy

Object.withDefault = (defaultValue, o = {}) => new Proxy (o, {get: (o, k) => (k in o)? O [k]: defaultValue}); o = Object.withDefault (42); öküz // => 42 öküz = 10 öküz // => 10 o.xx // => 42
Vlad V

Yani Proxy kullanmak aynı zamanda Object.getEntriesbir
Meredith

1
Yani Object.entries, işleyiciyi, erişildiğinde özellikleri ayarlamak için değiştirebilirsiniz. Değişim return target.hasOwnProperty(name) ? target[name] : 42;için if (!target.hasOwnProperty(name)) target[name] = 42; return target[name];.
dosentmatter

31

Yıkıcı kullanın (ES6'da yeni)

Sözdizimini benden daha iyi açıklayan harika bir blog yazısının yanı sıra Mozila'nın harika bir dokümantasyonu var .

Soruna cevap vermek için

var emptyObj = {};
const { nonExistingAttribute = defaultValue } = emptyObj;
console.log(nonExistingAttribute); // defaultValue

Daha ileri gitmek

Bu değişkeni yeniden adlandırabilir miyim ? Elbette!

const { nonExistingAttribute: coolerName = 15} = emptyObj;
console.log(coolerName); // 15

İç içe geçmiş veriler ne olacak? Bırakın gelsin!

var nestedData = {
    name: 'Awesome Programmer',
    languages: [
        {
            name: 'javascript',
            proficiency: 4,
        }
    ],
    country: 'Canada',
};

var {name: realName, languages: [{name: languageName}]} = nestedData ;

console.log(realName); // Awesome Programmer
console.log(languageName); // javascript

28

Bunu Javascript'te ayarlamanın bir yolu yoktur - undefinedvar olmayan özellikler için geri dönmek , temel Javascript spesifikasyonunun bir parçasıdır. Bu benzer soru için tartışmaya bakın . Orada önerdiğim gibi, bir yaklaşım (bunu gerçekten tavsiye edemeyecek olsam da) küresel bir getPropertyişlevi tanımlamak olacaktır :

function getProperty(o, prop) {
    if (o[prop] !== undefined) return o[prop];
    else return "my default";
}

var o = {
    foo: 1
};

getProperty(o, 'foo'); // 1
getProperty(o, 'bar'); // "my default"

Ancak bu, başkalarının okuması zor olacak bir grup standart dışı koda yol açar ve tanımlanamayan bir değer beklediğiniz veya istediğiniz alanlarda istenmeyen sonuçlara yol açabilir. Sadece giderken kontrol etmek daha iyi:

var someVar = o.someVar || "my default";

10
uyarı: var someVar = o.someVar || "my default";o.someVar doldurulduğunda ancak yanlış olarak değerlendirildiğinde (ör. null, 0, "") potansiyel olarak beklenmeyen sonuçlara sahip olacaktır. someVar = o.someVar === undefined ? o.someVar : "my default";Daha iyi olurdu. ||Varsayılan da false. (e.g. o.someVar || olarak değerlendirildiğinde genellikle tek başıma kullanırım. 0`)
Shanimal

5
Bu iyi bir nokta - bu, yanlış-y değerinin geçerli girdi olduğu hiçbir yerde işe yaramaz ve bu kalıbı kullanırken bunu göz önünde bulundurmanız gerekir. Ancak çoğu zaman, bir mülke açıkça ayarlanmış nullveya ayarlanmamış bir mülke falseaynı şekilde muamele etmek mantıklıdır , bu durumda bu, çifte görev yapar. Yine de uyarı adil.
nrabinowitz

5
@Shanimal Örneğiniz yanlış yol, öyle olmalı someVar = o.someVar === undefined ? "my default" : o.someVar;, sadece küçük bir sorun ama kodunuzu ilk denediğimde beni biraz
zorladı

evet @Metalskin tanımsız değeri umursamayacak mıydık? lol. üzgünüm, umarım hata size çok zaman
kaybettirmemiştir

11

Bu kesinlikle prototip tabanlı nesnelerin tipik kullanımına benziyor:

// define a new type of object
var foo = function() {};  

// define a default attribute and value that all objects of this type will have
foo.prototype.attribute1 = "defaultValue1";  

// create a new object of my type
var emptyObj = new foo();
console.log(emptyObj.attribute1);       // outputs defaultValue1

console.log (emptyObj) çağırırsanız, {} döndürür. not {attribute1: 'defaultValue1'}
throrin19

2
Evet, çünkü attribute1: defaultValue1prototip ve console.log üzerindedir, prototip üzerinde değil, yalnızca üst düzey nesnede ayarlanan öğeleri numaralandırır. Ama değer şovlarımda olduğu gibi orada console.log(emptyObj.attribute1).
jfriend00

doğru ama aynı sorun JSON.stringify(emptyobj). Bu soruna yanıt olarak tüm öznitelikleri döndüren bir yöntem oluşturmak zorunda kaldım
throrin19

11

benim kodum:

function(s){
    s = {
        top: s.top || 100,    // default value or s.top
        left: s.left || 300,  // default value or s.left
    }
    alert(s.top)
}

1
Bu çözümü en çok seviyorum, çünkü PHP'de yaptığıma benzer. function foo( array $kwargs = array() ) { // Fill in defaults for optional keyworded arguments. $kwargs += array( 'show_user' => true, 'show_links' => false, ); ...
Mike Finch

10

Bunu başarmamın yolu object.assignişlevdir

const defaultProperties = { 'foo': 'bar', 'bar': 'foo' };
const overwriteProperties = { 'foo': 'foo' };
const newObj = Object.assign({}, defaultProperties, overwriteProperties);
console.log(defaultProperties);  // {"foo": "bar", "bar": "foo"}
console.log(overwriteProperties);  // { "foo": "foo" };
console.log(newObj);  // { "foo": "foo", "bar": "foo" }

5
Bunu overwritePropertiesyaparak doğru şekilde değerlerin üzerine de yazıyorsunuz :const newObj = Object.assign({}, defaultProperties, overwriteProperties)
Francisco Puga

6

En basit yaklaşımın kullanmak olduğunu düşünüyorum Object.assign.

Bu sınıfa sahipseniz:

class MyHelper {
    constructor(options) {
        this.options = Object.assign({
            name: "John",
            surname: "Doe",
            birthDate: "1980-08-08"
        }, options);
    }
}

Bunu şu şekilde kullanabilirsiniz:

let helper = new MyHelper({ name: "Mark" });
console.log(helper.options.surname); // this will output "Doe"

Belgeler (çoklu dolgulu): https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Object/assign


6

Tüm Çözümlerin En Basiti:

dict = {'first': 1,
        'second': 2,
        'third': 3}

Şimdi,

dict['last'] || 'Excluded'

varsayılan değer olan "Hariç Tutuldu" sonucunu döndürür.


3
biraz farklı bir sözünüz varsa bu başarısız olur:dict = {'first': 0, 'second': 1, 'third': 2}
Vlad V

2
Bu aynı zamanda var olmayabilecek değerleri zincirlemek için harika bir yoldur. Örneğin a.b.c.d. A, d veya c tanımlanmamışsa bir hataya (((a || {}).b || {}).c || {}).d) || "default"
çarparsınız

1
Şimdiye kadar en iyi çözüm!
Arthur Harduim

5

Ya da bunu deneyebilirsin

dict = {
 'somekey': 'somevalue'
};

val = dict['anotherkey'] || 'anotherval';

15
Kötü bir fikir dict [ 'anotherKey'] 0. ise
Ray Toal

: Belki bu düşünmelisiniz codereadability.com/...
ebragaparah

@RayToal O zaman bunu String()düzeltmez mi? Şu şekilde:val = dict[String('anotherkey')] || 'anotherval';
Godstime Osarobo

Hayır, üzgünüm, olmaz. Aynı sorun. İlk yapın: Deneyin d = {x: 1, y: 0}ardından d['y'] || 100Sonra hangi fikrinizi denemek ve değil yanlışlıkla 100. verir d[String('y')] || 100- bu hala o 0. vermelidir zaman yanlış 100 verir
Ray Toal

4

Bu bana bunu yapmanın en basit ve okunabilir yolu gibi görünüyor:

let options = {name:"James"}
const default_options = {name:"John", surname:"Doe"}

options = Object.assign({}, default_options, options)

Object.assign () başvurusu


Alt çizgi kitaplığının bunun için _.defaults (nesne, * varsayılanlar) yöntemine sahip olduğunu yanıtlayacaktım, ancak cevabınız herhangi bir kitaplık olmadan aynı olacak!
DaniCE

2

Dün bir Object.__noSuchMethod__mülkten bahseden bir makale gördüm : JavascriptTips Onunla oynama şansım olmadı, bu yüzden tarayıcı desteğini bilmiyorum, ama belki bunu bir şekilde kullanabilirsin?


O sayfayı da gördüm, aynı HN makalesini okumuş olmalıyız. Yine de sadece yöntemler. DefineGetter ile yapılabilir ama bu ne yazık ki ECMA5'te değil. Benim görüşüme göre daha kötü olan başka bir alıcı / ayarlayıcı yaklaşımı ile değillerdi (önceden özelliklerin tanımlanmasını gerektirir).
sandstrom

Bu, gelecekte bir cevap olabilir :) Umarım tarayıcılar yakında oraya
ulaşır

1
Gelecekteki cevabın bir Proxy
James Long

@JamesLong evet, haklısınız! Gelecek geldi :) Soruyu sorduktan 3 yıl sonra bu artık FF'de (ve yakında diğer tarayıcılarda) çalışıyor. Aşağıya bir cevap ekledim.
sandstrom

2

Henüz kimsenin üçlü operatörden bahsetmemesine şaşırdım.

var emptyObj = {a:'123', b:'234', c:0};
var defaultValue = 'defaultValue';
var attr = 'someNonExistAttribute';
emptyObj.hasOwnProperty(attr) ? emptyObj[attr] : defaultValue;//=> 'defaultValue'


attr = 'c'; // => 'c'
emptyObj.hasOwnProperty(attr) ? emptyObj[attr] : defaultValue; // => 0

Bu şekilde 'c' değeri 0 olsa bile doğru değeri alacaktır.


1
Object.withDefault = (defaultValue,o={}) => {
  return new Proxy(o, {
    get: (o, k) => (k in o) ? o[k] : defaultValue 
  });
}

o = Object.withDefault(42);
o.x  //=> 42

o.x = 10
o.x  //=> 10
o.xx //=> 42

Yani ... Proxy kullanmak aynı zamanda tüm güzel Nesne yöntemlerini artık kaybedeceğiniz anlamına da gelir :(
Meredith

0

Bunu yapmak aslında mümkün Object.create. "Tanımlanmamış" özellikler için çalışmayacaktır. Ancak varsayılan bir değer verilmiş olanlar için.

var defaults = {
    a: 'test1',
    b: 'test2'
};

Ardından, özellikler nesnenizi oluşturduğunuzda, Object.create

properties = Object.create(defaults);

Şimdi, ilk nesnenin boş olduğu, ancak prototipin defaultsnesneyi işaret ettiği iki nesneniz olacak. Test etmek için:

console.log('Unchanged', properties);
properties.a = 'updated';
console.log('Updated', properties);
console.log('Defaults', Object.getPrototypeOf(properties));


-1

Buraya bir çözüm aramaya geldim çünkü başlık sorun açıklamamla eşleşti ama aradığım şey bu değil ama sorunuma bir çözüm buldum (tarih gibi dinamik bir özellik için varsayılan bir değer olmasını istedim ).

let Blog = {
title  : String,
image  : String,
body   : String,
created: {type: Date, default: Date.now}
}

Yukarıdaki kod, sonunda yerleştiğim çözümdü.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.