Lodash - .extend () / .assign () ve .merge () arasındaki fark


Yanıtlar:


583

Şöyle extend/ assignçalışır: Kaynaktaki her özellik için değerini olduğu gibi hedefe kopyalayın. özellik değerlerinin kendileri nesne ise, özelliklerinde özyinelemeli geçiş olmaz. Tüm nesne kaynaktan alınır ve hedefe ayarlanır.

Şöyle mergeçalışır: Kaynaktaki her özellik için, o özelliğin nesnenin kendisi olup olmadığını kontrol edin. Öyleyse, özyinelemeli olarak aşağı inin ve alt nesne özelliklerini kaynaktan hedefe eşlemeye çalışın. Yani esasen nesne hiyerarşisini kaynaktan hedefe birleştiriyoruz. extend/ İçin iken assign, özelliklerin kaynaktan hedefe basit bir düzeyli kopyasıdır.

İşte bu kristali netleştirecek basit JSBin: http://jsbin.com/uXaqIMa/2/edit?js,console

Örnekte dizi içeren daha ayrıntılı sürüm: http://jsbin.com/uXaqIMa/1/edit?js,console


16
Önemli bir fark, _.merge yeni bir birleştirilmiş nesneyi döndürürken, _.extend hedef nesneyi yerinde değiştirir,
letronje

69
İkisi de geri döndüklerinden bağımsız olarak hedef nesneyi değiştiriyor gibi görünüyor.
Jason Rice

7
Ayrıca, hedef nesnenin _.extend clobbers üyelerini, eğer beni şaşırtan kaynak nesnede yoksa görünüyorlar.
Jason Rice

5
@JasonRice Onlar zorla yakalanmıyorlar. Örneğin, bu kemanda, "a" özelliği tıkanmaz . Genişletmeden sonra, dest ["p"] ["y"] artık mevcut değil - Bunun nedeni, extend src ve dest'in her ikisinin de "p" özelliğine sahip olmasından dolayı dest'in "p" özelliğinin tamamen üzerine yazılmasıdır. src'nin "p" özelliğine göre (şimdi aynı nesnedirler).
Kevin Wheeler

14
Açık olmak gerekirse, her iki yöntem de referansla ilk argümanı değiştirir / üzerine yazar . Sonuçta ortaya çıkan birleştirmeden yeni bir nesne istiyorsanız, bir nesneyi gerçek anlamda geçirmek en iyisidir. var combined = merge({}, src, dest)
Jon Jaques

534

Lodash sürüm 3.10.1

Karşılaştırılan yöntemler

  • _.merge(object, [sources], [customizer], [thisArg])
  • _.assign(object, [sources], [customizer], [thisArg])
  • _.extend(object, [sources], [customizer], [thisArg])
  • _.defaults(object, [sources])
  • _.defaultsDeep(object, [sources])

benzerlikler

  • Hiçbiri beklediğiniz gibi dizilerde çalışmaz
  • _.extendiçin bir takma addır _.assign, bu yüzden aynıdırlar
  • Hepsi hedef nesneyi değiştiriyor gibi görünüyor (ilk argüman)
  • Hepsi nullaynı şekilde

farklılıklar

  • _.defaultsve _.defaultsDeepargümanları diğerlerine göre ters sırada işler (ilk argüman hala hedef nesne olsa da)
  • _.mergeve _.defaultsDeepalt nesneler birleştirilecek ve diğerleri kök seviyesinde üzerine yazılır
  • Yalnızca _.assignve _.extendile bir değerin üzerine yazılırundefined

Testler

Hepsi de kökten üyeleri benzer şekilde ele alıyor.

_.assign      ({}, { a: 'a' }, { a: 'bb' }) // => { a: "bb" }
_.merge       ({}, { a: 'a' }, { a: 'bb' }) // => { a: "bb" }
_.defaults    ({}, { a: 'a' }, { a: 'bb' }) // => { a: "a"  }
_.defaultsDeep({}, { a: 'a' }, { a: 'bb' }) // => { a: "a"  }

_.assignkolları undefinedama diğerleri atlayacak

_.assign      ({}, { a: 'a'  }, { a: undefined }) // => { a: undefined }
_.merge       ({}, { a: 'a'  }, { a: undefined }) // => { a: "a" }
_.defaults    ({}, { a: undefined }, { a: 'bb' }) // => { a: "bb" }
_.defaultsDeep({}, { a: undefined }, { a: 'bb' }) // => { a: "bb" }

Hepsi nullaynı şekilde

_.assign      ({}, { a: 'a'  }, { a: null }) // => { a: null }
_.merge       ({}, { a: 'a'  }, { a: null }) // => { a: null }
_.defaults    ({}, { a: null }, { a: 'bb' }) // => { a: null }
_.defaultsDeep({}, { a: null }, { a: 'bb' }) // => { a: null }

Ancak yalnızca _.mergeve _.defaultsDeepalt nesneleri birleştirir

_.assign      ({}, {a:{a:'a'}}, {a:{b:'bb'}}) // => { "a": { "b": "bb" }}
_.merge       ({}, {a:{a:'a'}}, {a:{b:'bb'}}) // => { "a": { "a": "a", "b": "bb" }}
_.defaults    ({}, {a:{a:'a'}}, {a:{b:'bb'}}) // => { "a": { "a": "a" }}
_.defaultsDeep({}, {a:{a:'a'}}, {a:{b:'bb'}}) // => { "a": { "a": "a", "b": "bb" }}

Ve hiçbiri dizileri birleştirmeyecek gibi görünüyor

_.assign      ({}, {a:['a']}, {a:['bb']}) // => { "a": [ "bb" ] }
_.merge       ({}, {a:['a']}, {a:['bb']}) // => { "a": [ "bb" ] }
_.defaults    ({}, {a:['a']}, {a:['bb']}) // => { "a": [ "a"  ] }
_.defaultsDeep({}, {a:['a']}, {a:['bb']}) // => { "a": [ "a"  ] }

Tümü hedef nesneyi değiştirir

a={a:'a'}; _.assign      (a, {b:'bb'}); // a => { a: "a", b: "bb" }
a={a:'a'}; _.merge       (a, {b:'bb'}); // a => { a: "a", b: "bb" }
a={a:'a'}; _.defaults    (a, {b:'bb'}); // a => { a: "a", b: "bb" }
a={a:'a'}; _.defaultsDeep(a, {b:'bb'}); // a => { a: "a", b: "bb" }

Hiçbiri dizilerde beklendiği gibi çalışmaz

Not: @Mistic'in işaret ettiği gibi, Lodash dizilere anahtarların dizinin dizini olduğu nesneler gibi davranır.

_.assign      ([], ['a'], ['bb']) // => [ "bb" ]
_.merge       ([], ['a'], ['bb']) // => [ "bb" ]
_.defaults    ([], ['a'], ['bb']) // => [ "a"  ]
_.defaultsDeep([], ['a'], ['bb']) // => [ "a"  ]

_.assign      ([], ['a','b'], ['bb']) // => [ "bb", "b" ]
_.merge       ([], ['a','b'], ['bb']) // => [ "bb", "b" ]
_.defaults    ([], ['a','b'], ['bb']) // => [ "a", "b"  ]
_.defaultsDeep([], ['a','b'], ['bb']) // => [ "a", "b"  ]

32
Aslında dizileri tam olarak nesneleri birleştirmiş gibi birleştirir, çünkü diziler sayısal anahtarları olan nesnelerdir. Birinin dizileri birleştirmeyi veya değiştirmeyi beklediğinin kullanıma bağlı olduğunu kabul ediyorum.
Mistic

11
Mükemmel cevap. Testler çok didaktikti :-)
Lucio Paiva

5
_.extend is an alias for _.assign, so they are identicalile çatışmalarOnly _.assign will overwrite a value with undefined
Chazt3n

9
V4.0 itibariyle, _.extend artık _assign değil, _.assignIn için bir diğer addır. AssignIn işlevi, devralınan özelliklerle uğraşmayı ekler.
Mike Hedman

2
null burada tanımlanmamış olanla aynı mı?
C_B

75

Dikkat edilmesi gereken bir diğer fark undefineddeğerlerin işlenmesidir :

mergeInto = { a: 1}
toMerge = {a : undefined, b:undefined}
lodash.extend({}, mergeInto, toMerge) // => {a: undefined, b:undefined}
lodash.merge({}, mergeInto, toMerge)  // => {a: 1, b:undefined}

Böylece değerleri tanımlı değerlerle mergebirleştirmeyeceğiz undefined.


3
Sadece ben mi yoksa lodash.extend'i her zaman 'toMerge' nesnesinin bir klonunu döndürmesi açısından tamamen işe yaramaz mı?
Jason Rice

6
Eğer mergeIntosahip olmayan özellikler toMergeolsaydı bu özellikleri koruyacaktı. Bu durumda bir klon olmazdı.
David Neale

1
@JasonRice boş {} kaldırmak ve yerinde birleştirir lodash.merge (mergeInto, toMerge)
sidonaldson

20

Semantik bir bakış açısıyla yaptıklarını düşünmek de yararlı olabilir:

_.atamak

   will assign the values of the properties of its second parameter and so on,
   as properties with the same name of the first parameter. (shallow copy & override)

_.birleştirmek

   merge is like assign but does not assign objects but replicates them instead.
  (deep copy)

_.defaults

   provides default values for missing values.
   so will assign only values for keys that do not exist yet in the source.

_.defaultsDeep

   works like _defaults but like merge will not simply copy objects
   and will use recursion instead.

Bu yöntemleri semantik açıdan düşünmeyi öğrenmenin, mevcut ve mevcut olmayan değerlerin tüm farklı senaryoları için nasıl bir davranış olacağını daha iyi "tahmin etmenizi" sağlayacağına inanıyorum.


3

Aynı objreferansı korurken geçersiz kılmadan derin bir kopya istiyorsanız

obj = _.assign(obj, _.merge(obj, [source]))

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.