Lodash - .extend() / .assign() 和 .merge() 之间的区别
IT技术
javascript
lodash
2021-02-05 22:18:19
5个回答
以下是extend
/ 的assign
工作原理:对于源中的每个属性,将其值按原样复制到目标。如果属性值本身是对象,则不会递归遍历它们的属性。整个对象将从源中取出并设置到目标中。
下面是如何merge
工作的:对于源的每个属性,检查如果该属性是对象本身。如果是,则递归向下并尝试将子对象属性从源映射到目标。所以本质上我们合并了从源到目标的对象层次结构。而对于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
是 的别名_.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" ]
另一个需要注意的区别是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
值合并为定义的值。
从语义的角度考虑它们的作用也可能会有所帮助:
_。分配
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)
_.默认值
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.
我相信学习从语义的角度思考这些方法会让你更好地“猜测”存在和不存在值的所有不同场景的行为。
如果您想要一个没有覆盖的深层复制同时保留相同的obj
引用
obj = _.assign(obj, _.merge(obj, [source]))