Cách nối các thuộc tính từ nhiều đối tượng JavaScript


105

Tôi đang tìm cách tốt nhất để "thêm" nhiều đối tượng JavaScript (mảng liên kết).

Ví dụ, đã cho:

a = { "one" : 1, "two" : 2 };
b = { "three" : 3 };
c = { "four" : 4, "five" : 5 };

cách tốt nhất để tính toán là gì:

{ "one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

3
Lưu ý về ngữ nghĩa: mặc dù có cú pháp [], chúng hoàn toàn không phải là mảng. Thứ tự không thực sự đảm bảo.
Álvaro González

1
Thứ tự lặp lại không được đảm bảo theo tiêu chuẩn ecma. Nhưng đó là cách nó được thực hiện trong hầu hết các trình duyệt. (Từ John Resig) Hành vi này không được xác định rõ ràng bởi đặc tả ECMAScript. Trong ECMA-262, phần 12.6.4: Cơ chế liệt kê các thuộc tính ... phụ thuộc vào việc triển khai. Tuy nhiên, đặc điểm kỹ thuật khá khác với việc thực hiện. Tất cả các triển khai hiện đại của ECMAScript đều lặp lại qua các thuộc tính đối tượng theo thứ tự mà chúng được xác định. Do đó, nhóm Chrome đã coi đây là một lỗi và sẽ sửa nó.
Juan Mendes

Câu trả lời:


159

ECMAscript 6 được giới thiệu Object.assign()để đạt được điều này nguyên bản trong Javascript.

Phương thức Object.assign () được sử dụng để sao chép các giá trị của tất cả các thuộc tính riêng có thể liệt kê từ một hoặc nhiều đối tượng nguồn sang một đối tượng đích. Nó sẽ trả về đối tượng đích.

Tài liệu MDN trên Object.assign ()

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 }

Object.assignđược hỗ trợ trong nhiều trình duyệt hiện đại nhưng không phải tất cả chúng. Sử dụng trình chuyển đổi như BabelTraceur để tạo JavaScript ES5 tương thích ngược.


4
Đây là một trong những điều tốt nhất tôi có thể nói. Vì E6 bây giờ chủ yếu được sử dụng, Object.assign là câu trả lời tốt nhất.
Vimalraj Selvam

6
Nếu bạn không biết có bao nhiêu đối tượng cần phải được hợp nhất, bevause họ đang ở trong một mảng, bạn có thể kết hợp chúng như sau:Object.assign.apply({}, [{a: 1}, {b: 2}, ....])
Jeanluca Scaljeri

1
Một thay thế cho việc sử dụng Object.assign.applysáp nhập một mảng của các đối tượng, là thay vì sử dụng các nhà điều hành lây lan:Object.assign( ...objects )
spen

@Spen đã được bao gồm như một câu trả lời cho câu hỏi này. Tôi không thấy lợi ích khi sao chép nó ở đây.
filoxo

sau 4 giờ, câu trả lời này đã giải quyết được vấn đề của tôi trong Angular 7. Cảm ơn vì sự đơn giản và chính xác của câu trả lời.
Gel

35

Bạn có thể sử dụng jquery $.extendnhư sau:

let a = { "one" : 1, "two" : 2 },
    b = { "three" : 3 },
    c = { "four" : 4, "five" : 5 };

let d = $.extend({}, a, b, c)

console.log(d)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


+1 Ngay cả khi bạn không sử dụng phương thức của jQuery, bạn có thể sử dụng mã của họ để giúp xây dựng triển khai của riêng bạn (có lẽ cụ thể hơn).
tvanfosson

25
@Randal: Có nhiều lý do hoàn toàn chính đáng để không sử dụng jQuery.
Tim Down

3
Chỉnh sửa:d = $.extend({},a,b,c);
Bob Stein,

34

Điều này nên làm điều đó:

function collect() {
  var ret = {};
  var len = arguments.length;
  for (var i = 0; i < len; i++) {
    for (p in arguments[i]) {
      if (arguments[i].hasOwnProperty(p)) {
        ret[p] = arguments[i][p];
      }
    }
  }
  return ret;
}

let a = { "one" : 1, "two" : 2 };
let b = { "three" : 3 };
let c = { "four" : 4, "five" : 5 };

let d = collect(a, b, c);
console.log(d);

Đầu ra:

{
  "one": 1,
  "two": 2,
  "three": 3,
  "four": 4,
  "five": 5
}

Không lengthtra cứu kích thước của mảng tại mỗi lần gọi? Tôi đã quá quen với việc viết lách đến for (var i = 0, len = array.length; i < len; ++i)nỗi tôi không thể nhớ hết lý do tại sao tôi lại bắt đầu làm việc đó.
tvanfosson

1
Vâng đúng rồi. Nó là hiệu suất tốt hơn để bộ nhớ cache độ dài một lần. Tuy nhiên, vì kích thước của các đối số "mảng" có thể không quá lớn, nó sẽ không thực sự quan trọng trong trường hợp này.
jhurshman

1
Không, ngoại trừ một chút trên IE6. Việc truy cập thuộc tính length có giá giống như truy cập biến len.
Alsciende

1
@Juan Tôi tin rằng bạn không chính xác, và tôi đã làm một số bài kiểm tra để quyết định. Lưu trữ độ dài là một huyền thoại dễ hiểu về tối ưu hóa đã lỗi thời trong nhiều năm và nó làm cho mã (hơi) ít dễ đọc hơn. Trên thực tế, độ dài bộ nhớ đệm đôi khi làm chậm trình duyệt (Safari).
Alsciende

2
Sẽ tốt hơn nếu viết 'for (var p in ...' thay vì 'for (p in ...' '?
Hugo

24

ECMAScript 6 có cú pháp lây lan . Và bây giờ bạn có thể làm điều này:

const obj1 = { 1: 11, 2: 22 };
const obj2 = { 3: 33, 4: 44 };
const obj3 = { ...obj1, ...obj2 };

console.log(obj3); // {1: 11, 2: 22, 3: 33, 4: 44}


12

Dấu gạch dưới có một số phương pháp để làm điều này;

1. _.extend (đích, * nguồn)

Sao chép tất cả các thuộc tính trong các đối tượng nguồn sang đối tượng đích và trả về đối tượng đích .

_.extend(a, _.extend(b, c));
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

Hoặc là

_.extend(a, b);
=> {"one" : 1, "two" : 2, "three" : 3}
_.extend(a, c);
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

2. _.defaults (đối tượng, * mặc định)

Điền vào các thuộc tính không xác định trong đối tượng với các giá trị từ các đối tượng mặc định và trả về đối tượng .

_.defaults(a, _.defaults(b, c));
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

Hoặc là

_.defaults(a, b);
=> {"one" : 1, "two" : 2, "three" : 3}
_.defaults(a, c);
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

4

Tại sao hàm bị giới hạn ở 3 đối số? Ngoài ra, hãy kiểm tra hasOwnProperty.

function Collect() {
    var o={};
    for(var i=0;i<arguments.length;i++) {
      var arg=arguments[i];
      if(typeof arg != "object") continue;
      for(var p in arg) {
        if(arg.hasOwnProperty(p)) o[p] = arg[p];
      }
    }
    return o;
}

4

Hiện có thể nhân bản nông (không bao gồm nguyên mẫu) hoặc hợp nhất các đối tượng bằng cách sử dụng cú pháp ngắn hơn Object.assign () .

Cú pháp Spread cho các ký tự đối tượng đã được giới thiệu trong ECMAScript 2018 ):

const a = { "one": 1, "two": 2 };
const b = { "three": 3 };
const c = { "four": 4, "five": 5 };

const result = {...a, ...b, ...c};
// Object { "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 }

Toán tử Spread (...) được hỗ trợ trong nhiều trình duyệt hiện đại nhưng không phải tất cả chúng.

Vì vậy, nó là khuyên bạn nên sử dụng một transpiler như Babel để chuyển đổi ECMAScript 2015+ mã vào một phiên bản tương thích ngược của JavaScript trong trình duyệt hoặc các môi trường hiện tại và cũ.

Đây là mã tương đương mà Babel sẽ tạo cho bạn:

"use strict";

var _extends = Object.assign || function(target) {
  for (var i = 1; i < arguments.length; i++) {
    var source = arguments[i];
    for (var key in source) {
      if (Object.prototype.hasOwnProperty.call(source, key)) {
        target[key] = source[key];
      }
    }
  }
  return target;
};

var a = { "one": 1, "two": 2 };
var b = { "three": 3 };
var c = { "four": 4, "five": 5 };

var result = _extends({}, a, b, c);
// Object { "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 }

Đây là một câu trả lời chắc chắn hơn nhiều so với câu trả lời được chấp nhận. Cảm ơn!
Kaleb Anderson

3
function Collect(a, b, c) {
    for (property in b)
        a[property] = b[property];

    for (property in c)
        a[property] = c[property];

    return a;
}

Lưu ý: Các thuộc tính hiện có trong các đối tượng trước đó sẽ bị ghi đè.


2
Điều này có tác dụng phụ a === dở cuối. Điều đó có thể ổn và có thể không.
tvanfosson

2

Thật dễ dàng khi sử dụng toán tử lây lan ES7 cho một đối tượng, trong bảng điều khiển trình duyệt của bạn

({ name: "Alex", ...(true  ? { age: 19 } : { })}) // {name: "Alex", age: 19}
({ name: "Alex", ...(false ? { age: 19 } : { })}) // {name: "Alex",        }

1
Đẹp. Câu hỏi này đã có hơn 10 năm, thật mừng vì giờ đây thao tác đơn giản như vậy đã trở nên dễ dàng. Trước đây không dễ dàng như vậy nếu bạn nhìn vào câu trả lời của người khác.
Vlad

đó là lý do tại sao tôi để lại câu trả lời của riêng mình :)
Purkhalo Alex

2

Để nhập một số năng động của các đối tượng, chúng ta có thể sử dụng Object.assignvới cú pháp lây lan .

const mergeObjs = (...objs) => Object.assign({}, ...objs);

Hàm trên chấp nhận bất kỳ số lượng đối tượng nào, hợp nhất tất cả các thuộc tính của chúng thành một đối tượng mới với các thuộc tính từ các đối tượng sau ghi đè lên các thuộc tính từ các đối tượng trước.

Bản giới thiệu:

Để hợp nhất một mảng đối tượng, một phương pháp tương tự có thể được áp dụng.

const mergeArrayOfObjs = arr => Object.assign({}, ...arr);

Bản giới thiệu:


1

Có thể, cách nhanh nhất, hiệu quả và chung chung hơn là cách này (bạn có thể hợp nhất bất kỳ số lượng đối tượng nào và thậm chí sao chép vào đối tượng đầu tiên -> gán):

function object_merge(){
    for (var i=1; i<arguments.length; i++)
       for (var a in arguments[i])
         arguments[0][a] = arguments[i][a];
   return arguments[0];
}

Nó cũng cho phép bạn sửa đổi đối tượng đầu tiên khi nó được truyền qua tham chiếu. Nếu bạn không muốn điều này nhưng muốn có một đối tượng hoàn toàn mới chứa tất cả các thuộc tính, thì bạn có thể chuyển {} làm đối số đầu tiên.

var object1={a:1,b:2};
var object2={c:3,d:4};
var object3={d:5,e:6};
var combined_object=object_merge(object1,object2,object3); 

Combit_object và object1 đều chứa các thuộc tính của object1, object2, object3.

var object1={a:1,b:2};
var object2={c:3,d:4};
var object3={d:5,e:6};
var combined_object=object_merge({},object1,object2,object3); 

Trong trường hợp này, đối tượng kết hợp chứa các thuộc tính của đối tượng1, đối tượng2, đối tượng3 nhưng đối tượng1 không được sửa đổi.

Kiểm tra tại đây: https://jsfiddle.net/ppwovxey/1/

Lưu ý: Các đối tượng JavaScript được chuyển bằng tham chiếu.


1

ES6 ++

Câu hỏi là thêm nhiều đối tượng khác nhau vào một.

let obj = {};
const obj1 = { foo: 'bar' };
const obj2 = { bar: 'foo' };
Object.assign(obj, obj1, obj2);
//output => {foo: 'bar', bar: 'foo'};

giả sử bạn có một đối tượng với nhiều khóa là các đối tượng:

let obj = {
  foo: { bar: 'foo' },
  bar: { foo: 'bar' }
}

đây là giải pháp tôi đã tìm thấy (vẫn phải nói trước: /)

let objAll = {};

Object.values(obj).forEach(o => {
  objAll = {...objAll, ...o};
});

Bằng cách này, chúng ta có thể thêm động TẤT CẢ các khóa đối tượng thành một.

// Output => { bar: 'foo', foo: 'bar' }

0

Đơn giản nhất: toán tử spread

var obj1 = {a: 1}
var obj2 = {b: 2}
var concat = { ...obj1, ...obj2 } // { a: 1, b: 2 }

-2
function collect(a, b, c){
    var d = {};

    for(p in a){
        d[p] = a[p];
    }
    for(p in b){
        d[p] = b[p];
    }
    for(p in c){
        d[p] = c[p];
    }

    return d;
}
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.