1. 程式人生 > >ES6中Object.assign() 方法

ES6中Object.assign() 方法

添加屬性 克隆對象 調用函數 rim 包裝 無法 ssi get 產生

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() 方法