Lodash – .extend()/ .assign()和.merge()之间的区别

在Lodash库中,有人可以提供合并和扩展/分配的更好的解释。

这是一个简单的问题,但答案回避我。

以下是extend / assign工作原理:对于源中的每个属性,将其值原样复制到目标。 如果属性值本身是对象,则不会recursion遍历它们的属性。 整个对象将从源获取并设置到目的地。

以下是merge工作原理:对于源代码中的每个属性,检查该属性是否是对象本身。 如果它是recursion下来,并尝试将源对象的子对象属性映射。 所以基本上我们合并了从源到目标的对象层次。 而对于extend / assign ,它是从源到目的地的简单属性级别的副本。

这里是简单的JSBin,这将使这清澈见底: http ://jsbin.com/uXaqIMa/2/edit?js, console

下面是更详细的版本,其中包括数组在示例中: http : //jsbin.com/uXaqIMa/1/edit?js,console

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_.extend的别名,所以它们是相同的
  • 他们都似乎修改目标对象(第一个参数)
  • 他们都处理null一样

差异

  • _.defaults_.defaultsDeep处理参数的顺序与其他顺序相反(尽pipe第一个参数仍然是目标对象)
  • _.merge_.defaultsDeep将合并子对象,其他的将在根级别覆盖
  • 只有_.assign_.extend会覆盖undefined的值

testing

他们都以类似的方式处理根源的成员。

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

要注意的另一个区别是处理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值合并到定义的值中。

从语义的angular度考虑他们做了什么也许是有帮助的:

_。分配

  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. 

我相信,从语义的angular度来学习这些方法会让你更好地“猜测”现有和不存在价值的所有不同场景的行为是什么。