MDN’s new design is in Beta! A sneak peek: https://blog.mozilla.org/opendesign/mdns-new-design-beta/

Object.assign()

This translation is incomplete. Please help translate this article from English.

Phương thức Object.assign() được sử dụng để copy giá trị của tất cả thuộc tính liệt kê được của một hoặc nhiều nguồn object đến một object mục tiêu. Nó sẽ  return object mục tiêu đó.

Cú pháp

Object.assign(target, ...sources)

Các thông số

target
object mục tiêu.
sources
object(s) nguồn.

Giá trị return

Object mục tiêu.

Mô tả

Các giá trị của object mục tiêu sẽ được ghi đè bởi các giá trị của các nguồn nếu chúng có chung khoá. Các thuộc tính nguồn sau đó cũng sẽ ghi đè lên các thuộc tính trước đó.

Phương thức Object.assign() chỉ sao chép những giá trịliệt kê được và là sở hữu của object nguồn đến object đích. Nó sử dụng  [[Get]] trên nguồn và [[Set]] trên mục tiêu, vì vậy nó sẽ gọi các getter và setter.  Do đó nó chỉ định giá trị thay vì chỉ sao chép hay xác định giá trị mới. Điều này có thể làm cho nó không phù hợp khi gộp các thuộc tính mới vào một nguyên mẫu (prototype) nếu nguồn gộp chứa các getter. Để sao chép các định nghĩa thuộc tính, bao gồm tính đếm được, bên trong prototype Object.getOwnPropertyDescriptor()Object.defineProperty() nên được sử dụng để thay thế.

Cả giá trị StringSymbol đều được sao chép.

Trong trường hợp lỗi, ví dụ nếu một thuộc tính không ghi được, một  TypeError  sẽ xuất hiện, và object đích sẽ không thay đổi gì. 

Chú ý rằng Object.assign() không vào được các giá trị nguồn mà null hoặc undefined.

Ví dụ

Sao chép một object

var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }

Cảnh báo cho Deep Clone

Với deep cloning, chúng ta cần sử dụng cách khác bởi vì Object.assign() sao chép các giá trị thuộc tính. Nếu giá trị nguồn là tham chiếu đến một object,  nó chỉ sao chép gía trị tham chiếu đó. 

function test() {
  'use strict';

  let a = { b: {c: 4} , d: { e: {f: 1} } };
  let g = Object.assign({}, a);
  let h = JSON.parse(JSON.stringify(a));
  console.log(JSON.stringify(g.d)); // { e: { f: 1 } }
  g.d.e = 32;
  console.log('g.d.e set to 32.'); // g.d.e set to 32.
  console.log(JSON.stringify(g)); // { b: { c: 4 }, d: { e: 32 } }
  console.log(JSON.stringify(a)); // { b: { c: 4 }, d: { e: 32 } }
  console.log(JSON.stringify(h)); // { b: { c: 4 }, d: { e: { f: 1 } } }
  h.d.e = 54;
  console.log('h.d.e set to 54.'); // h.d.e set to 54.
  console.log(JSON.stringify(g)); // { b: { c: 4 }, d: { e: 32 } }
  console.log(JSON.stringify(a)); // { b: { c: 4 }, d: { e: 32 } }
  console.log(JSON.stringify(h)); // { b: { c: 4 }, d: { e: 54 } }
}

test();

Gộp các object

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, object đích tự nó bị thay đổi.

Gộp các object với cùng giá trị

var o1 = { a: 1, b: 1, c: 1 };
var o2 = { b: 2, c: 2 };
var o3 = { c: 3 };

var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }

Các giá trị được ghi đè bởi các object khác có chung các thuộc tính sau này theo trình tự các thông số.

Sao chép giá trị symbol-typed

var o1 = { a: 1 };
var o2 = { [Symbol('foo')]: 2 };

var obj = Object.assign({}, o1, o2);
console.log(obj); // { a : 1, [Symbol("foo")]: 2 } (cf. bug 1207182 trên Firefox)
Object.getOwnPropertySymbols(obj); // [Symbol(foo)]

Không thể sao chép thuộc tính trên chuỗi prototype và các thuộc tính không liệt kê được. 

var obj = Object.create({ foo: 1 }, { // foo ở trên mắt xích prototype của obj.
  bar: {
    value: 2  // bar chứa thuộc tính không liệt kê được. 
  },
  baz: {
    value: 3,
    enumerable: true  // baz chứa thuộc tính liệt kê được.
  }
});

var copy = Object.assign({}, obj);
console.log(copy); // { baz: 3 }

Sự nguyên bản sẽ bị bao(wrap) các object

var v1 = 'abc';
var v2 = true;
var v3 = 10;
var v4 = Symbol('foo');

var obj = Object.assign({}, v1, null, v2, undefined, v3, v4); 
// Sự nguyên bản sẽ bị bao, null và undefined sẽ bị bỏ qua.
// Ghi chú,chỉ có string wrapper mới có thuộc tính liệt kê được. 
console.log(obj); // { "0": "a", "1": "b", "2": "c" }

Các trường hợp loại trừ sẽ phá huỷ nhiệm vụ sao chép

var target = Object.defineProperty({}, 'foo', {
  value: 1,
  writable: false
}); // target.foo chỉ read-only

Object.assign(target, { bar: 2 }, { foo2: 3, foo: 3, foo3: 3 }, { baz: 4 });
// TypeError: "foo" là read-only
// Trường hợp ngoại lệ được tạo ra khi gán target.foo

console.log(target.bar);  // 2, nguồn thứ nhất được sao chép thành công
console.log(target.foo2); // 3, đặc tính thứ nhất của nguồn thứ 2 được chép thành công.
console.log(target.foo);  // 1, sự loại trừ xuất hiện
console.log(target.foo3); // undefined, phương thức gán đã hoàn tấ, foo3 sẽ không bị sao chép
console.log(target.baz);  // undefined, nguồn thứ ba cũng không bị sao chép

Sao chép các trình truy cập (accessor)

var obj = {
  foo: 1,
  get bar() {
    return 2;
  }
};

var copy = Object.assign({}, obj); 
console.log(copy); 
// { foo: 1, bar: 2 }, giá trị của copy.bar là giá trị return của getter của obj.bar.

// Đây là function gán sao chép toàn bộ các mô tả. 
function completeAssign(target, ...sources) {
  sources.forEach(source => {
    let descriptors = Object.keys(source).reduce((descriptors, key) => {
      descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
      return descriptors;
    }, {});
    // Mặc định thì Object.assign sao chép cả Symbol thống kê được luôn
    Object.getOwnPropertySymbols(source).forEach(sym => {
      let descriptor = Object.getOwnPropertyDescriptor(source, sym);
      if (descriptor.enumerable) {
        descriptors[sym] = descriptor;
      }
    });
    Object.defineProperties(target, descriptors);
  });
  return target;
}

var copy = completeAssign({}, obj);
console.log(copy);
// { foo:1, get bar() { return 2 } }

Polyfill

 polyfill  không hỗ trợ các thuộc tính symbol, kể từ ES5 thì cũng không còn symbol nữa:

if (typeof Object.assign != 'function') {
  Object.assign = function(target, varArgs) { // .length của function là 2
    'use strict';
    if (target == null) { // TypeError nếu undefined hoặc null
      throw new TypeError('Cannot convert undefined or null to object');
    }

    var to = Object(target);

    for (var index = 1; index < arguments.length; index++) {
      var nextSource = arguments[index];

      if (nextSource != null) { // Bỏ qua nếu undefined hoặc null
        for (var nextKey in nextSource) {
          // Avoid bugs when hasOwnProperty is shadowed
          if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
    }
    return to;
  };
}

Đặc tính kỹ thuật

Specification Status Comment
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Object.assign' in that specification.
Standard Initial definition.
ECMAScript 2017 Draft (ECMA-262)
The definition of 'Object.assign' in that specification.
Draft  

Tương thích trình duyệt

Feature Chrome Firefox (Gecko) Internet Explorer Edge Opera Safari
Basic support 45 34 (34) No support (Yes) 32 9
Feature Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support No support 45 34.0 (34) No support No support (Yes)

See also

Document Tags and Contributors

 Contributors to this page: viiiprock
 Last updated by: viiiprock,