Soru İki JavaScript nesnesinin özelliklerini dinamik olarak nasıl birleştirebilirim?


Çalışma zamanında iki (çok basit) JavaScript nesnesini birleştirebilmem gerekir. Örneğin şunları yapmak istiyorum:

var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }

obj1.merge(obj2);

//obj1 now has three properties: food, car, and animal

Bunun için bir betik var mı, yoksa bunu yapmak için bir yol biliyor mu? Özyinelemeye ihtiyacım yok, ve fonksiyonları birleştirmem gerekmiyor, sadece düz nesneler üzerinde yöntemler.


1831


Menşei


Object.assign .... - caub


Cevaplar:


ECMAScript 2018 Standart Yöntem

Sen kullanır nesne yayıldı:

let merged = {...obj1, ...obj2};

/** There's no limit to the number of objects you can merge.
 *  Later properties overwrite earlier properties with the same name. */
const allRules = {...obj1, ...obj2, ...obj3};

ECMAScript 2015 (ES6) Standart Yöntem

/* For the case in question, you would do: */
Object.assign(obj1, obj2);

/** There's no limit to the number of objects you can merge.
 *  All objects get merged into the first object. 
 *  Only the object in the first argument is mutated and returned.
 *  Later properties overwrite earlier properties with the same name. */
const allRules = Object.assign({}, obj1, obj2, obj3, etc);

(görmek MDN JavaScript Referansı)


ES5 ve Daha Eski İçin Yöntem

for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }

Bunun sadece tüm özelliklerini içereceğini unutmayın. obj2 için obj1 hala değiştirilmemiş kullanmak istiyorsanız, ne istediğinizi olmayabilir obj1.

Tüm prototiplerin üzerinde çatlamış bir çerçeve kullanıyorsanız, o zaman hasOwnPropertyAncak bu kod vakaların% 99'u için çalışacaktır.

Örnek işlev:

/**
 * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
 * @param obj1
 * @param obj2
 * @returns obj3 a new object based on obj1 and obj2
 */
function merge_options(obj1,obj2){
    var obj3 = {};
    for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
    for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
    return obj3;
}

1898



Bu, nesnelerin aynı ad özelliklerine sahip olması durumunda işe yaramaz ve ayrıca öznitelikleri birleştirmek istersiniz. - Xiè Jìléi
Bu sadece sığ bir kopya / birleştirme yapar. Bir çok unsuru gizleme potansiyeline sahiptir. - Jay Taylor
Bazı fakir ruhların prototiplerinin her tarafına zarar veren çerçeveleri kullanmak zorunda kaldıklarını kabul etmek için +1 - thejonwithnoh
Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1 Bu, yeni bir nesne oluşturmanın gösterilen uygulamasıyla doğru değildir. - scones
Bu, benim için işe yaramadı çünkü "Bu nedenle, yeni özellikleri kopyalamak veya tanımlamak için özellikleri atar. Bu, birleştirme kaynakları içeriyorsa yeni özellikleri bir prototiple birleştirmek için uygun hale getirebilir." (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...). Kullanmak zorundaydım var merged = {...obj1, ...obj2}. - morgler


jQuery ayrıca bunun için bir yardımcı programa sahiptir: http://api.jquery.com/jQuery.extend/.

JQuery belgelerinden alınmıştır:

// Merge options object into settings object
var settings = { validate: false, limit: 5, name: "foo" };
var options  = { validate: true, name: "bar" };
jQuery.extend(settings, options);

// Now the content of settings object is the following:
// { validate: true, limit: 5, name: "bar" }

Yukarıdaki kod, mevcut nesne adlı settings.


Eğer oluşturmak istiyorsanız yeni nesne bağımsız değişkenleri değiştirmeden şunu kullanın:

var defaults = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };

/* Merge defaults and options, without modifying defaults */
var settings = $.extend({}, defaults, options);

// The content of settings variable is now the following:
// {validate: true, limit: 5, name: "bar"}
// The 'defaults' and 'options' variables remained the same.

1115



Tanrım, zayıf olarak adlandırılıyor. Nesneleri birleştirmeyi ararken onu bulmak pek olası değildir. - Gregory
Dikkat: Değişken "ayarlar" da olsa değiştirilecek. jQuery yeni bir örnek döndürmez. Bunun nedeni (ve adlandırma için) .extend (), nesneleri bir araya getirmek yerine, nesneleri genişletmek için geliştirilmiştir. Yeni bir nesne istiyorsanız (ör., Dokunmak istemediğiniz varsayılan ayarlardır) jQuery.extend ({}, ayarlar, seçenekler); - webmat
Dikkat et, jQuery.extend de derin (boolean) bir ayar var. jQuery.extend(true,settings,override)Bu, eğer bir özellik bir nesneyi tutarsa ​​ve geçersiz kılsa, bu nesnenin sadece bir parçası varsa önemlidir. Eşsiz özellikleri kaldırmak yerine, derin ayar yalnızca bulunduğu yerde güncellenir. Varsayılan yanlıştır. - vol7ron
benzer şekilde, alt çizgi.js kullanıyorsanız underscorejs.org/#extend - twmulloy
Gee Willikers, gerçekten bunu adlandıran iyi bir iş yaptılar. Javascript nesnesini nasıl genişleteceğinizi araştırırsanız hemen gelir! Javascript nesnelerini kaynaştırmaya veya birleştirmeye çalışıyorsanız, bunun üzerine çarpmayabilirsiniz. - Derek Greer


Harmony ECMAScript 2015 (ES6) belirtir Object.assign bunu yapacak.

Object.assign(obj1, obj2);

Mevcut tarayıcı desteği daha iyi olmakancak destek almamış tarayıcılar için geliştiriyorsanız, polyfill.


310



Bu sadece sığ birleştirme olduğunu unutmayın - Joachim Lous
Bence bu arada Object.assign oldukça iyi kapsama alanı var: kangax.github.io/compat-table/es6/... - LazerBass
Bu şimdi doğru cevap olmalı. Günümüzde insanlar bu tür bir şeyi desteklemeyen nadir tarayıcı (IE11) ile uyumlu olacak şekilde kodlarını derliyorlar. Yan not: obj1'e obj1 eklemek istemiyorsanız, yeni bir nesneyi kullanarak Object.assign({}, obj1, obj2) - Duvrai
@Duvrai Gördüğüm raporlara göre, IE11 kesinlikle nadir değil Temmuz 2016 itibarıyla pazar payının yaklaşık% 18'inde. - NanoWizard
@Kermani OP, özyinelemenin gereksiz olduğuna özellikle dikkat çekiyor. Bu nedenle, bu çözümün sığ bir birleşmeyi gerçekleştirdiğini bilmek faydalı olsa da, bu cevap olduğu gibi yeterlidir. JoachimLou'nun yorumu iyi hak edilmiş referanslar aldı ve gerektiğinde ekstra bilgi sağlıyor. Derin ve sığ birleştirme ve benzer konular arasındaki farkın bu tartışmanın kapsamı dışında olduğunu düşünüyorum ve diğer SO sorularına daha uygun. - NanoWizard


Nesne özellikleri birleştirmek için kod için googled ve burada sona erdi. Ancak, yinelemeli birleştirme için herhangi bir kod olmadığı için kendim yazdım. (Belki jQuery uzatma özyineli BTW nedir?) Her neyse, umarım başka biri de yararlı bulacaktır.

(Şimdi kod kullanmıyor Object.prototype :)

kod

/*
* Recursively merge properties of two objects 
*/
function MergeRecursive(obj1, obj2) {

  for (var p in obj2) {
    try {
      // Property in destination object set; update its value.
      if ( obj2[p].constructor==Object ) {
        obj1[p] = MergeRecursive(obj1[p], obj2[p]);

      } else {
        obj1[p] = obj2[p];

      }

    } catch(e) {
      // Property in destination object not set; create it and set its value.
      obj1[p] = obj2[p];

    }
  }

  return obj1;
}

Bir örnek

o1 = {  a : 1,
        b : 2,
        c : {
          ca : 1,
          cb : 2,
          cc : {
            cca : 100,
            ccb : 200 } } };

o2 = {  a : 10,
        c : {
          ca : 10,
          cb : 20, 
          cc : {
            cca : 101,
            ccb : 202 } } };

o3 = MergeRecursive(o1, o2);

Nesne o3 gibi üretir

o3 = {  a : 10,
        b : 2,
        c : {
          ca : 10,
          cb : 20,
          cc : { 
            cca : 101,
            ccb : 202 } } };

227



Güzel, ama önce nesnelerin derin bir kopyasını yapardım. Bu şekilde o1, nesneler referans olarak geçirildiği için de değiştirilecekti. - skerit
Aradığım şey buydu. Try catch ifadesine gitmeden önce obj2.hasOwnProperty (p) olup olmadığını kontrol ettiğinizden emin olun. Aksi takdirde, prototip zincirinde daha yukarıdan bir araya gelen başka bir saçmalıkla sonuçlanabilir. - Adam
Teşekkürler Markus. O1'in MergeRecursive tarafından da değiştirildiğini unutmayın, o halde sonunda o1 ve o3 aynıdır. Hiçbir şey vermezseniz daha sezgisel olabilir, bu nedenle kullanıcı ne sağladıklarını (o1) değiştirdiğini ve sonuca ulaştığını bilir. Ayrıca, örneğinizde, o1'de orijinal olmayan o2'ye bir şey eklemenin, o2 özelliklerinin o1'e eklendiğini göstermek (örnekte sunulan alternatif kodun altında bir başkası, örneğinizi kopyalarken) eklemeye değer olabilir. o1'de - ama seninki bu konuda çalışıyor. - pancake
@JonoRR - kendi kendine özyinelemeyi yapar: obj1 [p] = MergeRecursive (obj1 [p], obj2 [p]); - z8000
Bu iyi bir cevaptır, ancak çift kıskaçlar: 1) Hiçbir mantık istisnalara dayanmamalıdır; Bu durumda, atılan herhangi bir istisna öngörülemeyen sonuçlarla yakalanacaktır. 2) Orijinal nesnenin değiştirilmesinden beri, hiçbir şeyin geri dönülmemesiyle ilgili pancake'in yorumuna katılıyorum. İşte istisna mantığı olmayan bir jsFiddle örnek: jsfiddle.net/jlowery2663/z8at6knn/4 - Jeff Lowery - Jeff Lowery


Bunu not et underscore.js'ler extend-yöntem bunu bir tek katlı olarak yapar:

_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}

166



Bu örnek, anonim nesnelerle uğraşırken iyidir, ancak durum böyle değilse, webmat'ın jQuery cevabında yorum mutasyonlar hakkında uyarı, alt çizgi olarak da geçerlidir hedef nesneyi değiştirir. JQuery cevabı gibi, bu mutasyonu ücretsiz yapmak sadece boş bir nesneyi birleştirir: _({}).extend(obj1, obj2); - Abe Voelker
Neyi başarmaya çalıştığınıza bağlı olarak alaka düzeyi olan başka bir tane daha var: _.defaults(object, *defaults) Msgstr "Nesnede null ve undefined özelliklerini varsayılan nesnelerden gelen değerlerle doldur ve nesneyi döndür." - conny
Birçok kişi hedef nesneyi mutasyona uğratmakla ilgili yorum yapmış, ancak bir metodu yeni bir tane oluşturmak yerine, ortak bir model (örneğin dojoda) dojo.mixin (dojo.clone (myobj), {newpropertys:) eklemek demektir. myobj "}) - Colin D
Alt çizgi rasgele sayıdaki nesneyi alabilir, böylece orijinal nesnenin mutasyonunu önleyebilirsiniz var mergedObj = _.extend({}, obj1, obj2). - lobati


JQuery extend () öğesine benzer şekilde, aynı işleve sahip olursunuz angularjs:

// Merge the 'options' object into the 'settings' object
var settings = {validate: false, limit: 5, name: "foo"};
var options  = {validate: true, name: "bar"};
angular.extend(settings, options);

81



Ayrıca JQ kaynağından genişletin tanımını "ödünç alabilir" ... - juanmf
@juanmf ne için? - naXa
@naXa Ben sadece bu fn için bir lib eklemek istemiyorsanız bir seçenek olacağını düşünüyorum. - juanmf


Bugün nesneleri birleştirmem gerekiyor ve bu soru (ve cevaplar) bana çok yardımcı oldu. Bazı cevapları denedim, ama hiçbiri ihtiyaçlarıma uymadı, bu yüzden bazı cevapları bir araya getirdim, kendim ekledim ve yeni birleştirme fonksiyonuyla karşılaştım. İşte burada:

var merge = function() {
    var obj = {},
        i = 0,
        il = arguments.length,
        key;
    for (; i < il; i++) {
        for (key in arguments[i]) {
            if (arguments[i].hasOwnProperty(key)) {
                obj[key] = arguments[i][key];
            }
        }
    }
    return obj;
};

Bazı örnek kullanımlar:

var t1 = {
    key1: 1,
    key2: "test",
    key3: [5, 2, 76, 21]
};
var t2 = {
    key1: {
        ik1: "hello",
        ik2: "world",
        ik3: 3
    }
};
var t3 = {
    key2: 3,
    key3: {
        t1: 1,
        t2: 2,
        t3: {
            a1: 1,
            a2: 3,
            a4: [21, 3, 42, "asd"]
        }
    }
};

console.log(merge(t1, t2));
console.log(merge(t1, t3));
console.log(merge(t2, t3));
console.log(merge(t1, t2, t3));
console.log(merge({}, t1, { key1: 1 }));

59



Bu harika bir cevap! JQuery kaynak kodu gibi! - Progo
Tek soru etiketi javascriptBu yüzden tek doğru cevap ve aynı zamanda harika olanı. - skobaljic
iyi bir cevap ama sanırım ilk ve ikinci sırada bir özellik varsa ve birinci ve ikinci birleşerek yeni bir nesne yapmaya çalışıyorsanız, o zaman ilk nesnede bulunan benzersiz olanları kaybedeceksiniz. - Strikers
Ama beklenen davranış değil mi? Bu işlevin amacı argüman sırasındaki değerleri geçersiz kılar. Bir sonraki akım geçersiz olacaktır. Benzersiz değerleri nasıl koruyabilirsiniz? Örneğimden ne bekliyorsunuz? merge({}, t1, { key1: 1 })? - Emre Erkan
Benim beklentim, sadece nesne olmayan yazılan değerleri birleştirmektir. - AGamePlayer


Kullanabilirsiniz nesne yayılma özellikleri-Şu anda 3 ECMAScript teklifi.

const obj1 = { food: 'pizza', car: 'ford' };
const obj2 = { animal: 'dog' };

const obj3 = { ...obj1, ...obj2 };
console.log(obj3);


43



Tarayıcı desteği - Alph.Dev
@ Alph.Dev caniuse.com'u biliyor musunuz? - connexo
@connexo Hangi amaçla soruyorsunuz? Caniuse.com'daki JS nesne yayma özelliklerine uygun bağlantı sağlayın veya müdahale etmeyin. Bu akıllı eşek oynamak için bir yer değil. - Alph.Dev
Bu, herkesin kolayca kendi başına kontrol edebilecekleri şeyleri sormak için bir yer değil. - connexo
Node.js.'de çalışmak için 3 nokta sözdizimini alamıyorum. Düğüm bu konuda şikayet ediyor. - blackhawk