本文翻译自:Lodash - difference between .extend() / .assign() and .merge()
In the Lodash library, can someone provide a better explanation of merge and extend / assign . 在Lodash库中,有人可以提供合并和扩展/分配的更好解释。
Its a simple question but the answer evades me nonetheless. 这是一个简单的问题,但答案却避开了我。
#1楼
参考:https://stackoom.com/question/1Lm1k/Lodash-extend-assign-和-merge-之间的区别
#2楼
Here's how extend
/ assign
works: For each property in source, copy its value as-is to destination. 以下是extend
/ assign
工作原理:对于源中的每个属性,将其值按原样复制到目标。 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. 整个对象将从源中获取并设置到目标。
Here's how merge
works: For each property in source, check if that property is object itself. 以下是merge
工作原理:对于源中的每个属性,检查该属性是否为对象本身。 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. 对于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
#3楼
Another difference to pay attention to is handling of undefined
values: 要注意的另一个不同之处是处理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 merge
will not merge undefined
values into defined values. 因此merge
不会将undefined
值合并到定义的值中。
#4楼
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])
Similarities 相似
- None of them work on arrays as you might expect 它们都不像您期望的那样在数组上工作
-
_.extend
is an alias for_.assign
, so they are identical_.extend
是一个别名_.assign
,所以它们是相同的 - All of them seem to modify the target object (first argument) 所有这些似乎都修改了目标对象(第一个参数)
- All of them handle
null
the same 所有这些都处理null
相同
Differences 差异
-
_.defaults
and_.defaultsDeep
processes the arguments in reverse order compared to the others (though the first argument is still the target object) 与_.defaultsDeep
参数相比,_.defaults
和_.defaultsDeep
以相反的顺序处理参数(尽管第一个参数仍然是目标对象) -
_.merge
and_.defaultsDeep
will merge child objects and the others will overwrite at the root level_.merge
和_.defaultsDeep
将合并子对象,其他对象将在根级别覆盖 - Only
_.assign
and_.extend
will overwrite a value withundefined
只有_.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" }
_.assign
handles undefined
but 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 null
the 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 _.merge
and _.defaultsDeep
will 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" ]
#5楼
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 _.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. 我相信从语义的角度学习思考这些方法可以让你更好地“猜测”现有和非现有值的所有不同场景的行为。
#6楼
如果你想要一个没有覆盖的深拷贝,同时保留相同的obj
引用
obj = _.assign(obj, _.merge(obj, [source]))