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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19965844/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 17:22:53  来源:igfitidea点击:

Lodash - difference between .extend() / .assign() and .merge()

javascriptlodash

提问by JDillon522

In the Lodashlibrary, can someone provide a better explanation of mergeand extend / assign.

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

Its a simple question but the answer evades me nonetheless.

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

回答by Shital Shah

Here's how extend/assignworks: For each property in source, copy its value as-is to destination. if property values themselves are objects, there is no recursive traversal of their properties. Entire object would be taken from source and set in to destination.

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

Here's how mergeworks: For each property in source, check if that property is object itself. If it is then go down recursively and try to map child object properties from source to destination. So essentially we merge object hierarchy from source to destination. While for extend/assign, it's simple one level copy of properties from source to destination.

下面是如何merge工作的:对于源的每个属性,检查如果该属性是对象本身。如果是,则递归向下并尝试将子对象属性从源映射到目标。所以本质上我们合并了从源到目标的对象层次结构。而对于extend/ assign,它是从源到目标的简单属性的一级副本。

Here's simple JSBin that would make this crystal clear: http://jsbin.com/uXaqIMa/2/edit?js,console

这是一个简单的 JSBin,可以让这一切变得清晰:http://jsbin.com/uXaqIMa/2/edit?js, console

Here's more elaborate version that includes array in the example as well: http://jsbin.com/uXaqIMa/1/edit?js,console

这是示例中包含数组的更详细的版本:http: //jsbin.com/uXaqIMa/1/edit?js,console

回答by Nate

Lodash version 3.10.1

Lodash 版本3.10.1

Methods compared

方法比较

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

Similarities

相似之处

  • None of them work on arrays as you might expect
  • _.extendis an alias for _.assign, so they are identical
  • All of them seem to modify the target object (first argument)
  • All of them handle nullthe same
  • 它们都不能像您期望的那样在数组上工作
  • _.extend是 的别名_.assign,所以它们是相同的
  • 他们似乎都在修改目标对象(第一个参数)
  • 他们都处理null相同的

Differences

差异

  • _.defaultsand _.defaultsDeepprocesses the arguments in reverse order compared to the others (though the first argument is still the target object)
  • _.mergeand _.defaultsDeepwill merge child objects and the others will overwrite at the root level
  • Only _.assignand _.extendwill overwrite a value with undefined
  • _.defaults_.defaultsDeep以与其他参数相反的顺序处理参数(尽管第一个参数仍然是目标对象)
  • _.merge并且_.defaultsDeep将合并子对象和其他人将在根级别覆盖
  • 只有_.assign并且_.extend将覆盖一个值undefined

Tests

测试

They all handle members at the root in similar ways.

它们都以类似的方式处理根中的成员。

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

_.assignhandles undefinedbut the others will skip it

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

They all handle nullthe same

他们都处理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 }

But only _.mergeand _.defaultsDeepwill merge child objects

但是,只有_.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" }}

And none of them will merge arrays it seems

他们似乎都不会合并数组

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

All modify the target object

全部修改目标对象

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

None really work as expected on arrays

没有一个真正在数组上按预期工作

Note: As @Mistic pointed out, Lodash treats arrays as objects where the keys are the index into the array.

注意:正如@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"  ]

回答by samz

Another difference to pay attention to is handling of undefinedvalues:

另一个需要注意的区别是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}

So mergewill not merge undefinedvalues into defined values.

因此merge不会将undefined值合并为定义的值。

回答by epeleg

It might be also helpful to consider what they do from a semantic point of view:

从语义的角度考虑它们的作用也可能会有所帮助:

_.assign

_。分配

   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

_。合并

   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

_.defaultsDeep

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

I believe that learning to think of those methods from the semantic point of view would let you better "guess" what would be the behavior for all the different scenarios of existing and non existing values.

我相信学习从语义的角度思考这些方法会让你更好地“猜测”存在和不存在值的所有不同场景的行为。

回答by mbao01

If you want a deep copy without override while retaining the same objreference

如果您想要一个没有覆盖的深层复制同时保留相同的obj引用

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

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