咱們常常在別人的代碼中看見 assign
,extend
,merge
函數,這三個函數用起來很類似,都是合併源對象的屬性到目標對象中。git
既然都是合併對象,爲何還分三個不一樣的函數呢?它們之間到底有什麼區別呢?github
咱們先看看官方網站上面的定義:app
Assigns own enumerable string keyed properties of source objects to the destination object. Source objects are applied from left to right. Subsequent sources overwrite property assignments of previous sources.函數
把源對象(sources)的屬性分配到目標對象(object),源對象會從左往右地調用,後面對象的屬性會覆蓋前面的。網站
看看下面的例子:this
assign({}, { a: 1 }, { b: 2 }); // { a: 1, b: 2 } // 後面的 { a: 2 } 把前面的 { a: 1 } 覆蓋了 assign({}, { a: 1 }, { b: 2 }, { a: 2 }); // { a: 2, b: 2 } // 觀察下面兩個例子,若是屬性值爲 object,後面的值會覆蓋前面的值 assign( {}, { a: 1 }, { b: { c: 2, d: 3 } } ) // { a: 1, b: { c: 2, d: 3 } } assign( {}, { a: 1 }, { b: { c: 2, d: 3 } }, { b: { e: 4 } } ) // { a: 1, b: { e: 4 } } // `assign` 函數會忽略原型鏈上的屬性。 function Foo() { this.c = 3; } Foo.prototype.d = 4; assign({ a: 1 }, new Foo()); // { a: 1, c: 3 } // `assign` 會修改原來的對象 var test = { a: 1 }; assign(test, { b: 2 }); // { a: 1, b: 2 } console.log(test); // { a: 1, b: 2 }
在 3.x 版本中,extend
是 assign
的別名,它們的做用是如出一轍的。
在 4.x 版本中,extend
是 assignIn
的別名,和 assign
有點區別。prototype
官方定義以下:code
This method is like _.assign except that it iterates over own and inherited source properties.對象
在上面的例子中,咱們知道 assign
函數不會把原型鏈上的屬性合併到目標對象,而 extend
或 assignIn
函數則會!ip
// Important !! this is Lodash 4.x !! // 把源對象原型鏈上的屬性也合併到目標對象上! function Foo() { this.c = 3; } Foo.prototype.d = 4; extend({ a: 1 }, new Foo()); // { a: 1, c: 3, d: 4 }
咱們看看 merge
函數的定義:
This method is like _.assign except that it recursively merges own and inherited enumerable string keyed properties of source objects into the destination object. Source properties that resolve to undefined are skipped if a destination value exists. Array and plain object properties are merged recursively.Other objects and value types are overridden by assignment. Source objects are applied from left to right. Subsequent sources overwrite property assignments of previous sources.
merge
也和 assign
相似,不一樣的地方在於 merge
遇到相同屬性的時候,若是屬性值爲純對象(plain object)或者集合(collection)時,不是用後面的屬性值去覆蓋前面的屬性值,而是會把先後兩個屬性值合併。
若是源對象的屬性值爲 undefined
,則會忽略該屬性。
assign( {}, { a: 1 }, { b: { c: 2, d: 3} }, { b: { e: 4 } } ) // { a: 1, b: { e: 4 } } merge( {}, { a: 1 }, { b: { c: 2, d: 3} }, { b: { e: 4 } } ) // { a: 1, b: { c: 2, d: 3, e: 4 } } // 合併集合 var users = { 'data': [{ 'user': 'barney' }, { 'user': 'fred' }] }; var ages = { 'data': [{ 'age': 36 }, { 'age': 40 }] }; merge({}, users, ages) // { data: [ { user: 'barney', age: 36 }, { user: 'fred', age: 40 } ] } // merge 函數會修改原來的對象! merge(users, ages) console.log(users) // { data: [ { user: 'barney', age: 36 }, { user: 'fred', age: 40 } ]
均可以用來合併對象
都會修改原來的對象 (若是原來的對象是做爲函數的第一個參數的話)
assign
函數不會處理原型鏈上的屬性,也不會合並相同的屬性,而是用後面的屬性值覆蓋前面的屬性值
extend
3.x 版本中和 assign
同樣
4.x 版本中會合並原型鏈上的屬性
merge
遇到相同屬性名的時候,若是屬性值是純對象或集合的時候,會合並屬性值
http://scarletsky.github.io/2016/04/02/a...
https://lodash.com/docs
http://stackoverflow.com/questions/19965...