Lodash-.extend () / .assign () 및 .merge ()의 차이점


답변:


583

방법은 다음 extend/ assign대상에-그대로 소스의 각 속성에 대해 값을 복사 작동합니다. 속성 값 자체가 객체 인 경우 속성의 재귀 적 순회가 없습니다. 전체 객체는 소스에서 가져 와서 대상으로 설정됩니다.

merge작동 방식 은 다음과 같습니다 . 소스의 각 속성에 대해 해당 속성이 개체 자체인지 확인하십시오. 그렇다면 재귀 적으로 내려 가고 하위 객체 속성을 소스에서 대상으로 매핑하십시오. 따라서 기본적으로 객체 계층을 소스에서 대상으로 병합합니다. 에있는 동안 extend/ assign,이 소스로부터 목적지까지의 속성의 간단한 수준의 사본입니다.

이 수정을 명확하게하는 간단한 JSBin이 있습니다 : http://jsbin.com/uXaqIMa/2/edit?js,console

예제에 배열을 포함하는 더 정교한 버전이 있습니다. http://jsbin.com/uXaqIMa/1/edit?js,console


16
중요한 차이점은 _.merge가 새로운 병합 된 객체를 반환하는 반면 _.extend는 대상 객체를 제자리로 변경한다는 것입니다.
letronje

69
둘 다 반환 대상에 관계없이 대상 객체를 변경하는 것으로 보입니다.
Jason Rice

7
또한 _.extend는 대상 객체의 멤버가 소스 객체에없는 경우 클로버를 만드는 것으로 보입니다.
Jason Rice

5
@JasonRice 그들은 혼란스럽지 않습니다. 예를 들어이 바이올린에서 "a"속성은 방해받지 않습니다 . extend, dest [ "p"] [ "y"]가 더 이상 존재하지 않는 것은 사실입니다. 이는 extend src와 dest에 모두 "p"속성이 있기 때문에 dest의 "p"속성이 완전히 덮어 쓰기 때문입니다. src의 "p"속성에 의해 (이것은 현재 정확히 같은 객체입니다).
Kevin Wheeler

14
명확히하기 위해 두 방법 모두 첫 번째 인수를 참조로 수정 / 덮어 씁니다 . 따라서 결과 병합에서 새 객체를 원한다면 객체 리터럴을 전달하는 것이 가장 좋습니다. var combined = merge({}, src, dest)
Jon Jaques

534

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

31
배열은 숫자 키가있는 개체이기 때문에 실제로 개체를 병합하는 것과 똑같이 배열을 병합합니다. 사용에 따라 배열을 연결하거나 대체 할 것으로 예상합니다.
Mistic

11
훌륭한 답변입니다. 테스트는 매우 교훈적이었습니다 :-)
Lucio Paiva

5
_.extend is an alias for _.assign, so they are identical충돌Only _.assign will overwrite a value with undefined
Chazt3n

9
v4.0부터 _.extend는 이제 _assign이 아닌 _.assignIn의 별칭입니다. assignIn 함수는 상속 된 속성 처리를 추가합니다.
Mike Hedman

2
여기서 null은 정의되지 않은 것과 동일하게 취급됩니까?
C_B

75

주의해야 할 또 다른 차이점은 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
lodash.extend가 항상 'toMerge'개체의 복제본을 반환한다는 점에서 나에게만 해당됩니까?
Jason Rice

6
없는 mergeInto속성이있는 경우 toMerge해당 속성을 유지합니다. 이 경우 복제본이 아닙니다.
David Neale

1
@JasonRice 빈 {}을 제거하면 lodash.merge (mergeInto, toMerge)
sidonaldson에서

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.

_.defaultsDeep

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

시맨틱 관점에서 이러한 방법을 생각하는 법을 배우면 기존의 가치와 존재하지 않는 가치에 대한 모든 다른 시나리오에 대한 행동을 더 잘 추측 할 수 있다고 생각합니다.


3

동일한 obj참조 를 유지하면서 재정의없이 딥 카피를 원할 경우

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.