Lodash-.extend()/ .assign()と.merge()の違い


回答:


584

ここではどのようだextend/ assign宛先に-があるとして、ソースの各プロパティについて、その値をコピーします作品。プロパティ値自体がオブジェクトである場合、それらのプロパティの再帰的な走査はありません。オブジェクト全体がソースから取得され、宛先に設定されます。

ここではどのようだmergeそのプロパティは、オブジェクト自体である場合は、ソースの各プロパティについて、確認してください:作品。それが再帰的にダウンしている場合は、子オブジェクトのプロパティをソースから宛先にマップしてみてください。したがって、基本的には、オブジェクト階層をソースから宛先にマージします。用しながらextend/ assign、それは元から宛先へのプロパティの単純な1つのレベルのコピーです。

この結晶は明らかになるだろう。ここのシンプルなJSBin: http://jsbin.com/uXaqIMa/2/edit?js,console

以下は、例にも配列を含むより精巧なバージョンです:http : //jsbin.com/uXaqIMa/1/edit?js,console


16
重要な違いは、_。mergeが新しいマージされたオブジェクトを返す一方で、_。extendは宛先オブジェクトをインプレースで変更することです
letronje

70
どちらも、何を返すかに関係なく、宛先オブジェクトを変更するように見えます。
Jason Rice

7
_.extendが宛先オブジェクトのメンバーをソースオブジェクトに存在しない場合、それらのメンバーが不思議に思っていることもわかります。
Jason Rice

5
@JasonRice彼らは壊滅しません。たとえば、このフィドルでは、 "a"プロパティは破棄されません。拡張後、dest ["p"] ["y"]はもはや存在しないことは事実です-これは、拡張前にsrcとdestの両方に "p"プロパティがあったため、destの "p"プロパティが完全に上書きされるためですsrcの "p"プロパティによる(現在はまったく同じオブジェクトです)。
Kevin Wheeler

14
明確にするために、どちらの方法も参照によって最初の引数を変更/上書きします。したがって、結果のマージから新しいオブジェクトが必要な場合は、オブジェクトリテラルを渡すのが最善です。var combined = merge({}, src, dest)
Jon Jaques 2016年

535

Lodashバージョン3.10.1

比較した方法

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

類似点

  • あなたが期待するようにそれらのどれも配列で機能しません
  • _.extendのエイリアスであるため_.assign、同じです
  • それらのすべてがターゲットオブジェクトを変更しているようです(最初の引数)
  • それらはすべてnull同じように処理します

違い

  • _.defaults及び_.defaultsDeep(最初の引数は依然として目標オブジェクトであるが)、他と比較して逆の順序で引数を処理します
  • _.mergeそして、_.defaultsDeep子オブジェクトをマージし、他の人がルートレベルに上書きされます
  • のみ_.assign_.extend値を上書きしますundefined

テスト

これらはすべて、ルートのメンバーを同様の方法で処理します。

_.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"  }

_.assign処理しますundefinedが、他の人はそれをスキップします

_.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" }

彼らはすべてnull同じように扱います

_.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 }

ただし_.merge_.defaultsDeep子オブジェクトのみをマージします

_.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" }}

そして、それらのどれもそれが思われる配列をマージしません

_.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"  ] }

すべてターゲットオブジェクトを変更します

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" }

アレイで期待どおりに機能するものは実際にはありません

注:@Misticが指摘したように、Lodashは配列を、キーが配列へのインデックスであるオブジェクトとして扱います。

_.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
配列は数値キーを持つオブジェクトなので、実際にはオブジェクトをマージするのとまったく同じように配列をマージします。配列を連結または置換することを期待することは、使用法に依存することに同意します。
ミスティック

11
すばらしい答えです。テストは非常に教訓的でした:-)
Lucio Paiva

5
_.extend is an alias for _.assign, so they are identical競合Only _.assign will overwrite a value with undefined
Chazt3n

9
v4.0以降、_。extendは_assignではなく_.assignInのエイリアスになりました。assignIn関数は、継承されたプロパティの処理を追加します。
Mike Hedman、2016年

2
nullはここで未定義と同じように扱われますか?
C_B 2017

75

注意すべきもう1つの違いは、undefined値の処理です。

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

したがって、値を定義済みの値にmergeマージしませんundefined


3
それは私だけですか、それとも常に「toMerge」オブジェクトのクローンを返すという点でlodash.extendは完全に役に立たないのですか?
Jason Rice

6
mergeInto持っていなかったプロパティがある場合は、toMergeそれらのプロパティが保持されます。その場合、それはクローンではありません。
David Neale、2015

1
@JasonRiceは空の{}を削除し、それを所定の場所にマージしますlodash.merge(mergeInto、toMerge)
sidonaldson

20

セマンティックの観点から彼らが何をするかを検討することも役立つでしょう:

_。割当

   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)

_。マージ

   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.

セマンティックの観点からこれらのメソッドについて考えることを学ぶことで、既存の値と存在しない値のさまざまなシナリオすべての動作をより正確に「推測」できると思います。


3

同じobj参照を保持しながら、オーバーライドなしのディープコピーが必要な場合

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.