Lodash 中 assign,extend 和 merge 的區別
來自: http://scarletsky.github.io/2016/04/02/assign-vs-extend-vs-merge-in-lodash/
我們經常在別人的代碼中看見 assign , extend , merge 函數,這三個函數用起來很相似,都是合并源對象的屬性到目標對象中。
既然都是合并對象,為什么還分三個不同的函數呢?它們之間到底有什么區別呢?
assign(object, [sources])
我們先看看官方網站上面的定義:
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),源對象會從左往右地調用,后面對象的屬性會覆蓋前面的。
看看下面的例子:
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 }
extend(object, [sources])
在 3.x 版本中, extend 是 assign 的別名,它們的作用是一模一樣的。
在 4.x 版本中, extend 是 assignIn 的別名,和 assign 有點區別。
官方定義如下:
This method is like _.assign except that it iterates over own and inherited source properties.
在上面的例子中,我們知道 assign 函數不會把原型鏈上的屬性合并到目標對象,而 extend 或 assignIn 函數則會!
// 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(object, [sources])
我們看看 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 } ]
總結
相同之處
- 都可以用來合并對象
- 都會修改原來的對象 (如果原來的對象是作為函數的第一個參數的話)