首页 文章

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

提问于
浏览
409

Lodash库中,有人可以提供mergeextend / assign的更好解释 .

这是一个简单的问题,但答案却避开了我 .

4 回答

  • 18

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

  • 515

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

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

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

    我相信,从语义的角度学习思考这些方法可以让你更好地“猜测”现有和非现有值的所有不同场景的行为 .

  • 72

    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处理未定义但其他人将跳过它

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

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

    以下是 merge 的工作原理:对于源中的每个属性,检查该属性是否为对象本身 . 如果它然后递归下去并尝试将子对象属性从源映射到目标 . 基本上我们将对象层次结构从源合并到目标 . 而对于 extend / assign ,它是从源到目标的简单的一级属性副本 .

    这里简单的JSBin将使这一点变得清晰:http://jsbin.com/uXaqIMa/2/edit?js,console

    这里有更复杂的版本,包括示例中的数组:http://jsbin.com/uXaqIMa/1/edit?js,console

相关问题