在Lodash库中,有人可以更好地解释merge和extend / assign。
这是一个简单的问题,但答案却避开了我。
答案 0 :(得分:541)
以下是extend
/ assign
的工作原理:对于源中的每个属性,将其值按原样复制到目标。如果属性值本身是对象,则不会对其属性进行递归遍历。整个对象将从源获取并设置到目标。
以下是merge
的工作原理:对于源中的每个属性,检查该属性是否为对象本身。如果它然后递归下去并尝试将子对象属性从源映射到目标。基本上我们将对象层次结构从源合并到目标。对于extend
/ assign
,它是从源到目标的简单的一级属性副本。
这是一个简单的JSBin,可以使这个结晶清晰: http://jsbin.com/uXaqIMa/2/edit?js,console
这里有更复杂的版本,包括示例中的数组: http://jsbin.com/uXaqIMa/1/edit?js,console
答案 1 :(得分:472)
_.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" ]
答案 2 :(得分:73)
要注意的另一个不同之处是处理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 :(得分: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)
provides default values for missing values.
so will assign only values for keys that do not exist yet in the source.
works like _defaults but like merge will not simply copy objects
and will use recursion instead.
我相信从语义角度学习思考这些方法可以让你更好地“猜测”现有和非现有值的所有不同场景的行为。
答案 4 :(得分:0)
如果您想在不覆盖的情况下进行深拷贝,同时保留相同的obj
参考
obj = _.assign(obj, _.merge(obj, [source]))