Làm cách nào để hợp nhất hai đối tượng javascript lại với nhau trong ES6 +?


141

Tôi phát chán vì luôn phải viết mã như thế này:

function shallowExtend(obj1,obj2){
  var key;
  for ( key in obj2 ) {
    if ( obj2.hasOwnProperty(key) === false )  continue;
    obj1[key] = obj2[key]
  }
}

Hoặc nếu tôi không muốn tự viết mã, hãy triển khai một thư viện đã thực hiện nó. Chắc chắn ES6 + đang đến để giải cứu về vấn đề này sẽ cung cấp cho chúng ta một cái gì đó giống như một Object.prototype.extend(obj2...)hoặcObject.extend(obj1,obj2...)

Vậy ES6 + có cung cấp chức năng như vậy không? Nếu chưa có, chức năng như vậy đã được lên kế hoạch chưa? Nếu không có kế hoạch thì tại sao không?


3
Vậy tại sao bạn chưa thêm nó vào thư viện của bạn ?
RobG

12
@RobG câu hỏi này là về hy vọng ES6 sẽ loại bỏ chúng ta khỏi việc phải cần đến cái nồi hơi như vậy ngay từ đầu. Cho những gì đáng giá: github.com/balupton/bal-util/blob/iêu
balupton

Tôi không nghĩ có một cách chung để sao chép các cặp tên / giá trị từ đối tượng này sang đối tượng khác. Bạn chỉ đối phó với tài sản riêng hoặc những người trong [[Prototype]]chuỗi? Bạn có làm bản sao "sâu" hay "nông" không? Điều gì về các đặc tính có thể ghi được và không phải là không có gì? Tôi nghĩ rằng tôi muốn có một chức năng thư viện nhỏ làm những gì tôi cần, và chủ yếu là nó có thể tránh được.
RobG

Câu trả lời:


206

Bạn sẽ có thể thực hiện hợp nhất / mở rộng / gán nông trong ES6 bằng cách sử dụng Object.assign:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Cú pháp:

Object.assign ( mục tiêu , nguồn );

trong đó ... nguồn đại diện cho (các) đối tượng nguồn.

Thí dụ:

var obj1 = {name: 'Daisy', age: 30};
var obj2 = {name: 'Casey'};

Object.assign(obj1, obj2);

console.log(obj1.name === 'Casey' && obj1.age === 30);
// true

64
Một lưu ý nhỏ: Object.assign làm thay đổi mục tiêu. Nếu đó không phải là những gì bạn muốn, bạn có thể gọi nó bằng một đối tượng trống:let merged = Object.assign({}, source1, source2);
david

20
Xin lưu ý rằng đây là một phần mở rộng nông ... các đối tượng lồng nhau KHÔNG được hợp nhất
monzonj

@monzonj, không có tùy chọn nào để mở rộng các đối tượng lồng nhau, mà không sử dụng lodash hoặc mout?
Joao Falcao

1
Có một cách tốt để hợp nhất các đối tượng được lồng sâu mà không cần thư viện chỉ bằng cách sử dụng Object.assign: xem câu trả lời của tôi ở đây
Ruslan

Một cách cũ để mở rộng các đối tượng lồng nhau đang sử dụngJSON.parse(JSON.stringify(src))
Andre Figueiredo

162

Bạn có thể sử dụng cú pháp trải rộng đối tượng cho việc này:

const merged = {...obj1, ...obj2}

Đối với mảng, toán tử trải rộng đã là một phần của ES6 (ES2015), nhưng đối với các đối tượng, nó đã được thêm vào đặc tả ngôn ngữ tại ES9 (ES2018). Đề xuất của nó như được bật theo mặc định trong các công cụ như Babel từ lâu trước đó.


3
Không có chính thức nó được gọi là ES2015 bây giờ: P Kể từ khi phá hủy không phải là một phần của ES6? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/NH Chạy nút babel: const ob1 = {foo: 123}; const ob2 = {bar: 234}; const merged = {...ob1, ...ob2}; console.log(merged) Kết quả:{ foo: 123, bar: 234 }
Thijs Koerselman

9
Điều đó không phá hủy, nó lan rộng - và không, đối với các đối tượng, nó không phải là một phần của ES6. Bạn nên vô hiệu hóa các bản nháp ES7 thử nghiệm trong babel của bạn.
Bergi

2
Ah tha thứ cho tôi. Bạn đúng rồi. Đó là một tính năng babel giai đoạn 2 tại thời điểm này. github.com/sebmarkbage/ecmascript-rest-s lây lan Tôi chưa bao giờ nhận ra rằng vì tôi đã sử dụng nó từ đầu với babel và nó được bật theo mặc định. Nhưng vì dù sao bạn cũng cần phải dịch mã, và đối tượng lây lan là một điều khá đơn giản nên tôi sẽ khuyên bạn nên dùng nó. Tôi thích nó.
Thijs Koerselman

Họ được bật theo mặc định, thực sự? Nghe có vẻ như một lỗi.
Bergi

2
"Các đề xuất ở giai đoạn 2 trở lên được bật theo mặc định". babeljs.io/docs/usage/experimental
Thijs Koerselman

13

Tôi biết đây là một vấn đề cũ nhưng giải pháp đơn giản nhất trong ES2015 / ES6 thực sự khá đơn giản, sử dụng Object.assign (),

Hy vọng rằng điều này sẽ giúp, điều này cũng không hợp nhất DEEP :

/**
 * Simple is object check.
 * @param item
 * @returns {boolean}
 */
export function isObject(item) {
  return (item && typeof item === 'object' && !Array.isArray(item) && item !== null);
}

/**
 * Deep merge two objects.
 * @param target
 * @param source
 */
export function mergeDeep(target, source) {
  if (isObject(target) && isObject(source)) {
    for (const key in source) {
      if (isObject(source[key])) {
        if (!target[key]) Object.assign(target, { [key]: {} });
        mergeDeep(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    }
  }
  return target;
}

Ví dụ sử dụng:

mergeDeep(this, { a: { b: { c: 123 } } });
// or
const merged = mergeDeep({a: 1}, { b : { c: { d: { e: 12345}}}});  
console.dir(merged); // { a: 1, b: { c: { d: [Object] } } }

7

Việc bổ sung Object.mixinhiện đang được thảo luận để quan tâm đến hành vi mà bạn đang yêu cầu. https://mail.mozilla.org/pipermail/es-discuss/2012-December/027037.html

Mặc dù nó chưa có trong bản nháp ES6, nhưng có vẻ như có rất nhiều hỗ trợ cho nó, vì vậy tôi nghĩ rằng nó sẽ sớm xuất hiện trong bản nháp.


13
.mixinđã bị TC39 bỏ.
Knu

5
Cảnh báo - câu trả lời này không còn đúng nữa, hãy xem câu trả lời của Jack để biết cách tiếp cận chính xác và hiệu quả.
Benjamin Gruenbaum

Object.mixin đã được thay thế bởi Object.assign
gotofritz

7

ES6

Object.assign(o1,o2) ; 
Object.assign({},o1,o2) ; //safe inheritance
var copy=Object.assign({},o1); // clone o1
//------Transform array of objects to one object---
var subjects_assess=[{maths:92},{phy:75},{sport:99}];
Object.assign(...subjects_assess); // {maths:92,phy:75,sport:99}

ES7 hoặc Babel

{...o1,...o2} // inheritance
 var copy= {...o1};

1
@FilipBartuzi không phải ES6 mà bạn đã liên kết. Nhưng về cơ bản, nó đang làm tương đương với _.extend () trong lodash / gạch dưới.
Nỗi nhớ.io

5

Có lẽ Object.definePropertiesphương pháp ES5 sẽ thực hiện công việc?

ví dụ

var a = {name:'fred'};
var b = {age: {value: 37, writeable: true}};

Object.defineProperties(a, b);

alert(a.age); // 37

Tài liệu MDN: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperies


Hãy cẩn thận, mặc dù. Trên ít nhất một trình duyệt này có ý nghĩa về hiệu suất.
Reuben Morais

1
Tôi nghĩ phần thú vị nhất là definePropertiesđịnh nghĩa các thuộc tính riêng. Nó không ghi đè lên các thuộc tính trên [[prototype]]chuỗi, nó làm mờ chúng.
RobG

2
Đề xuất tốt, mặc dù không thực sự là một phần mở rộng vì nó là nhiều hơn để xác định cách các thuộc tính nên hành xử ... Thực hiện một Object.defineProperies đơn giản (obj1, obj2) sẽ gây ra kết quả không mong muốn.
balupton

cũng sẽ phải sử dụng Object.getOwnPropertyDescriptorđể đặt thuộc tính khi nó là một giá trị phức tạp hoặc bạn sẽ sao chép bằng cách tham chiếu.
dmp
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.