Nesneleri birleştirme (ilişkilendirilebilir diziler)


147

İki ilişkilendirilebilir diziyi JavaScript'te birleştirmenin en iyi / standart yolu nedir? Herkes sadece kendi fordöngüsünü kırarak mı yapıyor?


10
javascript btw'de ilişkilendirilebilir diziler yoktur, yalnızca nesneler vardır.
gblazex

Aynı soru Perl'de de
çapraz sorulur

Javascript'teki ilişkilendirilebilir diziler: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Chris Martin

Yanıtlar:


204

jquery ile arayabilirsiniz $.extend

var obj1 = {a: 1, b: 2};
var obj2 = {a: 4, c: 110};

var obj3 = $.extend(obj1, obj2); 

obj1 == obj3 == {a: 4, b: 2, c: 110} // Pseudo JS

(dernek dizileri js cinsinden nesnelerdir)

buraya bakın: http://api.jquery.com/jQuery.extend/


edit: önerilen rymo gibi, bu şekilde yapmak daha iyidir:

obj3 = $.extend({}, obj1, obj2); 
obj3 == {a: 4, b: 2, c: 110}

Burada olduğu gibi obj1 (ve obj2) değişmeden kalır.


edit2: 2018'de bunu yapmanın yolu şöyledir Object.assign:

var obj3 = Object.assign({}, obj1, obj2); 
obj3 === {a: 4, b: 2, c: 110} // Pseudo JS

ES6 ile çalışıyorsanız bu Spread Operator ile elde edilebilir :

const obj3 = { ...obj1, ...obj2 };

54
veya mucking önlemek için obj1, hedef olarak boş bir nesne kullanın:$.extend({}, obj1, obj2)
rymo

Evet, referanslarla iletilen kapaklar ve nesnelerle uğraşırken, sonraki işlemler için orijinal nesneyi etkilemekten kaçınmak için rymo'nun tavsiyelerini alın.
Nathan Smith

2
Modern tarayıcılar için, Object.assign()zaten kitaplığı kullanmıyorsanız JQuery'ye dayanmayan , @manfred kullanarak çözümü kontrol edin .
Phil

Çalışır, ancak ilk parametreyi değiştirir ve bu bilmeniz gereken bir şeydir. Bkz. Developer.mozilla.org/tr-TR/docs/Web/JavaScript/Reference/…
kulpae


49

Prototip bunu şu şekilde yapar:

Object.extend = function(destination, source) {
    for (var property in source) {
        if (source.hasOwnProperty(property)) {
            destination[property] = source[property];
        }
    }
    return destination;
};

olarak adlandırılır, örneğin:

var arr1 = { robert: "bobby", john: "jack" };
var arr2 = { elizabeth: "liz", jennifer: "jen" };

var shortnames = Object.extend(arr1,arr2);

EDIT : yorumlarda bucabay tarafından doğru şekilde işaretlenmiş hasOwnProperty () denetimi eklendi


6
Yalnızca hemen özellikleri kopyaladığınızdan emin olmak için test source.hasOwnProperty (özellik) gerekir. Olduğu gibi, bu Object.prototype
bucabay

22

Basit tutun ...

function mergeArray(array1,array2) {
  for(item in array1) {
    array2[item] = array1[item];
  }
  return array2;
}

6
arrau1.prototype
LeeGee

@LeeGee haklı. Bu hasOwnPropertykontrole ihtiyacınız var . Nesnelere diziler olarak atıfta bulunulması da yanıltıcıdır (nesnelerdir), arg adları dizi2'nin mutasyona uğradığını veya yeni bir nesnenin döndürülmesi gerektiğini belirtmelidir. Cevabı düzenlerdim ama aslında Jonathan Fingland'ın düzeltilmiş olan düzeltilmiş yanıtı neredeyse tam olarak olurdu .
Vaz

14

Alt çizgi ayrıca bir genişletme yöntemine sahiptir:

Kaynak nesnelerdeki tüm özellikleri hedef nesneye kopyalayın. Sırayla, bu nedenle son kaynak önceki bağımsız değişkenlerde aynı adın özelliklerini geçersiz kılar.

_.extend(destination, *sources) 

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


6

adlar aynı, ancak değerler aynı değilse bir özelliğin üzerine yazmak istiyor musunuz?

Orijinal nesnelerden birini kalıcı olarak değiştirmek ister misiniz?

veya yeni bir birleştirilmiş nesnenin döndürülmesini mi istiyorsunuz?

function mergedObject(obj1, obj2, force){
    for(var p in obj1) this[p]= obj1[p];
    for(var p in obj2){
        if(obj2.hasOwnProperty(p)){
            if(force || this[p]=== undefined) this[p]= obj2[p];
            else{
                n= 2;
                while(this[p+n]!== undefined)++n;
                this[p+n]= obj2[p];
            }
        }
    }
}

6

Kendi Uzatma / Karıştırma İşlevinizi Yuvarlama

function extend(objects) {
    var args
        , first = Array.prototype.slice.call(arguments, 0, 1)[0]
        , second;

    if (arguments.length > 1) {
        second = Array.prototype.splice.call(arguments, 1, 1)[0];
        for (var key in second) {
            first[key] = second[key];
        }
        args = Array.prototype.slice.call(arguments, 0);
        return extend.apply(this, args);
    }

    return first;
}

...

var briansDirections = {
    step1: 'Remove pastry from wrapper.',
    step2: 'Place pastry toaster.',
    step3: 'Remove pastry from toaster and enjoy.',
};
extend(briansDirections, { step1: 'Toast Poptarts' }, { step2: 'Go ahead, toast \'em' }, { step3: 'Hey, are you sill reading this???' });

...

Bu sadece bir uzanır uyarısı yinelemeli, nesnelerin. Ayrıca, bu özyinelemeli fonksiyonun TCO ( Kuyruk Çağrısı Optimize Edildi ) olduğuna dikkat edin, çünkü dönüşü kendisine yapılan son çağrıdır.

Ayrıca, hedeflenen özellikler isteyebilirsiniz . Bu durumda, nesnelere dayalı nesneleri yoğunlaştırmak isteyebilirsiniz id,quantity ya da başka bir özellik. Bu yaklaşım hakkında yazılmış küçük bir kitap olabilir ve nesne yan yana yerleştirilmesini gerektirir ve çok karmaşık olabilir. Bunun için talep üzerine küçük bir kütüphane yazdım.

Bu yardımcı olur umarım!


4
  1. Javascript'te ilişkilendirilebilir dizi kavramı yoktur, nesneler vardır
  2. İki nesneyi birleştirmenin tek yolu özellikleri ve işaretçileri için ilkel tür olmayan değerlere döngü yapmak ve ilkel türlerin değerlerini başka bir örneğe kopyalamaktır

8
Javascript'teki nesneler ilişkilendirilebilir diziler olarak uygulanır, bu yüzden kesinlikle aynı kavram vardır
Dexygen

2

2019'da 2 iyi seçeneğiniz var:

Nesne atama [ doc ]

const result = Object.assign({}, baseObject, updatingObject);

Nesne yayma [ doc ]

const result = { ...baseObject, ...updatingObject};

İlki daha güvenli, daha standart ve çok değerlikli olma eğilimindedir. İyi bir lehte ve aleyhte burada


1

Yahoo UI (YUI) ayrıca bunun için bir yardımcı işleve sahiptir:

http://developer.yahoo.com/yui/examples/yahoo/yahoo_merge.html

YAHOO.namespace('example');

YAHOO.example.set1 = { foo : "foo" };
YAHOO.example.set2 = { foo : "BAR", bar : "bar" };
YAHOO.example.set3 = { foo : "FOO", baz : "BAZ" };

var Ye = YAHOO.example;

var merged = YAHOO.lang.merge(Ye.set1, Ye.set2, Ye.set3);

1

jquery derin kopya için bir boole sahiptir. Böyle bir şey yapabilirsiniz:

MergeRecursive = function(arr1, arr2){
    $.extend(true, arr1, arr2);
    return arr1;                
};

Ayrıca birleştirmek üzere n-dizilerini desteklemek için bu işlevi düzenleyebilirsiniz.

ArrayMergeRecursive = function(){
     if(arguments.length < 2){
          throw new Error("ArrayMergeRecursive: Please enter two or more objects to merge!");
     }

    var arr1=arguments[0];
    for(var i=0; i<=arguments.length; i++ ){
        $.extend(true, arr1, arguments[i]);                 
    }

    return arr1;                
};

Şimdi yapabilirsin

var arr1 = {'color': {'mycolor': 'red'}, 3: 5},
    arr2 = {4: 10, 'color': {'favorite': 'green', 0: 'blue'}},
    arr3 = ['Peter','Jhon','Demosthenes'],
    results = ArrayMergeRecursive(arr1, arr2, arr3); // (arr1, arr2 ... arrN)
console.log("Result is:", results);

0

Derin nesne birleştirme ihtiyacım vardı. Yani diğer tüm cevaplar bana pek yardımcı olmadı. _.extend ve jQuery.extend, benim gibi yinelemeli bir diziniz olmadığı sürece iyi yapar. Ama o kadar da kötü değil, beş dakika içinde programlayabilirsiniz:

var deep_merge = function (arr1, arr2) {
    jQuery.each(arr2, function (index, element) {
        if (typeof arr1[index] === "object" && typeof element === "object") {
            arr1[index] = deep_merge(arr1[index], element);
        } else if (typeof arr1[index] === "array" && typeof element === "array") {
            arr1[index] = arr1[index].concat(element);
        } else {
            arr1[index] = element;
        }
    });
    return arr1;
}

0

JQuery'de dizileri birleştirmek için $ .merge?

var merged = $.merge([{id:3, value:'foo3'}], [{id:1, value:'foo1'}, {id:2, value:'foo2'}]);
merged[0].id == 3;
merged[0].value == 'foo3';
merged[1].id == 1;
merged[1].value == 'foo1';
merged[2].id == 2;
merged[2].value == 'foo2';

0

Özyinelemeli çözüm (nesnelerin dizilerini de genişletir) + boş işaretli

var addProps = function (original, props) {
    if(!props) {
        return original;
    }
    if (Array.isArray(original)) {
        original.map(function (e) {
            return addProps(e, props)
        });
        return original;
    }
    if (!original) {
        original = {};
    }
    for (var property in props) {
        if (props.hasOwnProperty(property)) {
            original[property] = props[property];
        }
    }
    return original;
};

Testler

console.log(addProps([{a: 2}, {z: 'ciao'}], {timestamp: 13}));
console.log(addProps({single: true}, {timestamp: 13}));
console.log(addProps({}, {timestamp: 13}));
console.log(addProps(null, {timestamp: 13}));

[ { a: 2, timestamp: 13 }, { z: 'ciao', timestamp: 13 } ]
{ single: true, timestamp: 13 }
{ timestamp: 13 }
{ timestamp: 13 }

Bunu Node JS ile kullanmayı denedim, ancak Object.getOwnPropertyNames is not a functionuygulamayı kilitleyeceğim.
Legoless

Ben plv8 PostgreSQL uzantısı içinde bazı oldish v8 motoru ile kullanıyorum. Ve tarayıcılarda çalışır. JS motorunuzda "hasOwnProperty" olarak eşdeğer bir şey yapmanın bir yolunu bulmanız yeterli. Sonra bu mantığı yeniden kullanabilirsiniz.
sscarduzio

0

İşte en iyi çözüm.

obj1.unshift.apply( obj1, obj2 );

Ayrıca, obj1herhangi bir sorun olmadan bir döngü içinde büyüyebilir. (diyelim ki obj2dinamik)

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.