ES6中Object.assign() 方法
ES6中Object.assign() 方法
1. 對象合並
Object.assign 方法用於對象的合並,將源對象(source)的所有可枚舉屬性,復制到目標對象上。
如下代碼演示:
var target = {a: 0}; var source1 = {b: 1}; var source2 = {c: 2}; Object.assign(target, source1, source2); console.log(target); // 輸出 {a: 0, b: 1, c: 2}
1-1 如果目標對象與源對象有同名屬性,或多個源對象有同名屬性,則後面的屬性會覆蓋前面的屬性。
var target = {a: 0, b: 1}; var source1 = {a:1, b: 2, c:3}; var source2 = {c:5}; Object.assign(target, source1, source2); console.log(target); // 輸出 {a: 1, b: 2, c: 5}
1-2 如果只有一個target(目標對象),Object.assign會直接返回該對象,如下代碼:
var o = {a: 0}; Object.assign(o); console.log(o); // {a: 0}
1-3
先是這樣的,正常的返回是number類型。
var a = 1; Object.assign(a); console.log(a); // 1 console.log(typeof a); // number
然後直接判斷類型,返回的是object類型
console.log(typeof Object.assign(2)) // object
1-4 對於null, undefined 來說 無法轉換成Object,就會在控制臺下報錯,如下代碼:
Object.assign(null); // 報錯 Object.assign(undefined); //報錯
1-5 對象合並,如果源對象是null的話或者是undefined的話,那麽對象合並的時候不會報錯,直接會跳過該對象的合並,直接返回目標對象。
如下代碼:
var obj = {a: 1}; console.log(Object.assign(obj, null) === obj); // true console.log(obj); // {a: 1} var obj = {a: 1}; console.log(Object.assign(obj, undefined) === obj); // true console.log(obj); // {a: 1}
1-6 如果是數值,布爾型,和字符串合並對象的話,都不會報錯,但是字符串會以數組的形式表現。
先看數值合並對象如下代碼:
var obj = {a: 1}; console.log(Object.assign(obj, 12) === obj); // true console.log(obj); // {a: 1}
布爾型合並對象如下代碼:
var obj = {a: 1}; console.log(Object.assign(obj, true) === obj); // true console.log(obj); // {a: 1}
字符串合並對象如下代碼:
var obj = {a: 1}; console.log(Object.assign(obj, "bcd") === obj); // true console.log(obj); // {0: ‘b‘, 1: ‘c‘, 2: ‘d‘, a: 1}
如上代碼,只有字符串和對象合並,這是因為只有字符串有包裝對象,會產生可枚舉類型屬性。比如如下代碼:
console.log(Object(‘bcd‘)); // {0: "b", 1: "c", 2: "d", length: 3, [[PrimitiveValue]]: "bcd"} console.log(Object(1111)); // {[[PrimitiveValue]]: 1111} console.log(Object(true)); // {[[PrimitiveValue]]: true}
上面代碼可以看到原始值都在包裝對象的內部屬性[[PrimitiveValue]]上,這個屬性沒有被Object.assign合並,只有字符串的包裝對象會產生可枚舉的屬性,屬性則會被合並。
但是Object.assign合並的屬性是有限的,只合並對象的自身的屬性(不合並繼承屬性),也不合並不可枚舉的屬性。
2. Object.assign方法是淺拷貝
因此Object.assign方法是淺復制,不是深復制,也就是說,如果源對象某個屬性的值是對象,那麽目標對象拷貝的是這個對象的引用。
比如如下代碼:
var o1 = {a: {b: 1} }; var o2 = Object.assign({}, o1); o1.a.b = 2; console.log(o2.a.b); // 2
如上代碼,o1是一個對象,該對象的屬性也是一個對象,使用Object.assign拷貝o1對象到o2上來,然後手動改變o1對象的屬性值,那麽o2對象的屬性值也會被改變。
但是如果對象的屬性值不是一個對象的話,那麽就不會影響該值,如下代碼:
var o1 = {a: 1}; var o2 = Object.assign({}, o1); o1.a = 2; console.log(o1); // {a: 2} console.log(o2.a); // 1
但是如果源對象和目標對象有同名屬性的話,那麽Object.assign會直接替換該屬性。比如如下代碼:
var target = {a: {b: 1}}; var source1 = {a: {b: ‘hello‘}}; Object.assign(target, source1); console.log(target); // {a: {b: ‘hello‘}}
註意:Object.assign可以用來處理數組,但是會把數組視為對象。
也就是說對象裏面有鍵值對索引,如果把兩個數組合並的話,那麽得到不是合並後新增的數組,而是會把對應相同的鍵替換掉,如下使用數組的demo代碼如下:
var targetArrs = [1, 2, 3]; var sourceArrs = [4, 5]; Object.assign(targetArrs, sourceArrs); console.log(targetArrs); // [4, 5, 3]
如上代碼,目標對象有1,2,3屬性,源對象有4,5值,如果使用Object.assign的話,那麽源對象的鍵4,5 和目標對象的1,2鍵是相同的,因此值直接替換掉。
3. Object.assign 常見使用在哪些地方?
3-1 為對象添加屬性。比如如下代碼:
class A { constructor(x, y) { Object.assign(this, {x, y}); } }
如上方法通過Object.assign方法,將x屬性和y屬性添加到A類的對象實列中。
3-2 為對象添加方法
Object.assign(A.prototype, { xMethod(x, y) { ... }, yMethod() { } }); // 相當於如下代碼: A.prototype.xMethod = function(x, y) {}; A.prototype.yMethod = function() {}
3-3 克隆對象
function clone(obj) { return Object.assign({}, obj); }
3-4 合並多個對象
如下一開始的代碼:
var target = {a: 0}; var source1 = {b: 1}; var source2 = {c: 2}; Object.assign(target, source1, source2); console.log(target); // 輸出 {a: 0, b: 1, c: 2}
4. 對象深度克隆
淺度克隆和深度克隆的含義如下:
淺度克隆: 原始類型為值傳遞,對象類型為引用傳遞。
深度克隆: 所有元素或屬性都是完全復制的,與原對象完全脫離,也就是說所有對於源對象的修改都不會反映到新對象中。反之,所有對於新對象的修改也不會反映到源對象中。
註意:Object.assign 是淺度克隆的。
4-1 ES5中我們可以通過遞歸的方式去調用函數來實現深度克隆。
代碼如下:
function deepClone(obj) { var newObj = obj instanceof Array ? [] : {}; for (var i in obj) { newObj[i] = Object.prototype.toString.call(obj[i]) === "[object Object]" ? deepClone(obj[i]) : obj[i]; } return newObj; } var obj = {a: {b: 1} }; var newObj = deepClone(obj); console.log(newObj); // 打印輸出 {a: {b: 1}} // 修改對象 obj obj.a.b = 2; console.log(obj); // 打印輸出 {a: {b: 2}} console.log(newObj); // 打印輸出 {a: {b: 1}} 原對象的修改不會影響到新對象中
如上面的代碼,在JS中,我們使用遞歸的方式,循環遍歷對象的所有屬性和方法,實現深度克隆,因此當我們深度克隆到新對象中的時候,再去更改源對象的屬性值的時候,不會影響到新對象。
ES6中Object.assign() 方法