Sáp nhập các đối tượng (mảng kết hợp)


147

Cách tốt nhất / tiêu chuẩn để hợp nhất hai mảng kết hợp trong JavaScript là gì? Có phải tất cả mọi người chỉ làm điều đó bằng cách lăn forvòng lặp của riêng mình ?


10
không có mảng kết hợp trong btw javascript, chỉ có các đối tượng.
gblazex

Crossref cùng một câu hỏi trong Perl: stackoverflow.com/questions3530018/iêu
dreftymac

Câu trả lời:


204

với jquery bạn có thể gọi $.extend

var obj1 = {a: 1, b: 2};
var obj2 = {a: 4, c: 110};

var obj3 = $.extend(obj1, obj2); 

obj1 == obj3 == {a: 4, b: 2, c: 110} // Pseudo JS

(PGS. mảng là đối tượng trong js)

xem tại đây: http://api.jquery.com/jQuery.extend/


chỉnh sửa: Giống như rymo đề xuất, tốt hơn là làm theo cách này:

obj3 = $.extend({}, obj1, obj2); 
obj3 == {a: 4, b: 2, c: 110}

Như ở đây obj1 (và obj2) vẫn không thay đổi.


chỉnh sửa2: Năm 2018 cách thực hiện là thông qua Object.assign:

var obj3 = Object.assign({}, obj1, obj2); 
obj3 === {a: 4, b: 2, c: 110} // Pseudo JS

Nếu làm việc với ES6, điều này có thể đạt được với Toán tử trải rộng :

const obj3 = { ...obj1, ...obj2 };

54
hoặc để tránh mucking obj1, sử dụng một đối tượng trống làm mục tiêu:$.extend({}, obj1, obj2)
rymo

Có, khi xử lý các lần đóng cửa và các đối tượng được chuyển qua tham chiếu, hãy đưa ra lời khuyên của rymo để tránh ảnh hưởng đến đối tượng ban đầu cho các hoạt động tiếp theo.
Nathan Smith

2
Đối với các trình duyệt hiện đại, hãy kiểm tra giải pháp bằng cách @manfred sử dụng Object.assign(), điều này không phụ thuộc vào JQuery nếu bạn chưa sử dụng thư viện.
Phil

Nó hoạt động, nhưng nó thay đổi tham số đầu tiên và đó là điều bạn cần phải biết. Xem developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/iêu
kulpae

62

Bây giờ trong năm 2016 tôi sẽ nói cách tốt nhất / tiêu chuẩn là Object.assign ()
Pure Javascript. Không cần jQuery.

obj1 = {a: 1, b: 2};
obj2 = {a: 4, c: 110};
obj3 = Object.assign({},obj1, obj2);  // Object {a: 4, b: 2, c: 110}

Thêm thông tin, ví dụ và polyfill tại đây:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign


Loại obj3 là gì? Nếu obj1 là loại IABC, thì obj3 sẽ giữ loại đó sau đó?
Windmaomao

49

Đây là cách Prototype thực hiện:

Object.extend = function(destination, source) {
    for (var property in source) {
        if (source.hasOwnProperty(property)) {
            destination[property] = source[property];
        }
    }
    return destination;
};

được gọi là, ví dụ:

var arr1 = { robert: "bobby", john: "jack" };
var arr2 = { elizabeth: "liz", jennifer: "jen" };

var shortnames = Object.extend(arr1,arr2);

EDIT : đã thêm hasOwnProperty () kiểm tra như được chỉ ra chính xác bởi bucabay trong các nhận xét


6
Bạn sẽ cần nguồn kiểm tra.hasOwnProperty (thuộc tính) để đảm bảo bạn chỉ sao chép các thuộc tính ngay lập tức. Như vậy, điều này có thể sẽ sao chép tất cả các thuộc tính bao gồm cả các thuộc tính có nguồn gốc từ Object.prototype
bucabay

22

Giữ cho nó đơn giản ...

function mergeArray(array1,array2) {
  for(item in array1) {
    array2[item] = array1[item];
  }
  return array2;
}

6
Bạn kiểm tra hasOwnProperty để tránh sao chép bất kỳ thuộc tính nào trênarrau1.prototype
LeeGee

@LeeGee nói đúng. Bạn cần hasOwnPropertykiểm tra. Việc đề cập đến các đối tượng là các mảng cũng gây hiểu nhầm (chúng là các đối tượng), các tên arg sẽ truyền tải rằng mảng2 bị đột biến hoặc một đối tượng mới sẽ được trả về. Tôi sẽ chỉnh sửa câu trả lời nhưng thực tế nó sẽ trở thành gần như chính xác câu trả lời đã được chỉnh sửa của Jonathan Fingerland đã được sửa.
Vaz

14

Underscore cũng có một phương thức mở rộng:

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. Đó là theo thứ tự, vì vậy nguồn cuối cùng sẽ ghi đè các thuộc tính cùng tên trong các đối số trước đó.

_.extend(destination, *sources) 

_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}


6

Bạn có muốn ghi đè lên một thuộc tính nếu tên giống nhau nhưng giá trị không?

Và bạn có muốn thay đổi vĩnh viễn một trong các đối tượng ban đầu không,

hoặc bạn muốn một đối tượng hợp nhất mới được trả lại?

function mergedObject(obj1, obj2, force){
    for(var p in obj1) this[p]= obj1[p];
    for(var p in obj2){
        if(obj2.hasOwnProperty(p)){
            if(force || this[p]=== undefined) this[p]= obj2[p];
            else{
                n= 2;
                while(this[p+n]!== undefined)++n;
                this[p+n]= obj2[p];
            }
        }
    }
}

6

Chức năng mở rộng / Mixin của riêng bạn

function extend(objects) {
    var args
        , first = Array.prototype.slice.call(arguments, 0, 1)[0]
        , second;

    if (arguments.length > 1) {
        second = Array.prototype.splice.call(arguments, 1, 1)[0];
        for (var key in second) {
            first[key] = second[key];
        }
        args = Array.prototype.slice.call(arguments, 0);
        return extend.apply(this, args);
    }

    return first;
}

...

var briansDirections = {
    step1: 'Remove pastry from wrapper.',
    step2: 'Place pastry toaster.',
    step3: 'Remove pastry from toaster and enjoy.',
};
extend(briansDirections, { step1: 'Toast Poptarts' }, { step2: 'Go ahead, toast \'em' }, { step3: 'Hey, are you sill reading this???' });

...

Điều này chỉ đơn giản là mở rộng một biểu tượng của các đối tượng, đệ quy. Ngoài ra, lưu ý rằng chức năng đệ quy này là TCO ( Tối ưu hóa cuộc gọi đuôi ) vì sự trở lại của nó là cuộc gọi cuối cùng với chính nó.

Ngoài ra, bạn có thể muốn các thuộc tính được nhắm mục tiêu . Trong trường hợp này, bạn có thể muốn ngưng tụ đối tượng dựa trên id, quantityhoặc tài sản khác. Cách tiếp cận này có thể có một cuốn sách nhỏ viết về nó và yêu cầu định vị đối tượng và có thể rất phức tạp. Tôi đã viết một thư viện nhỏ cho cái này có sẵn theo yêu cầu.

Hi vọng điêu nay co ich!


4
  1. Trong Javascript không có khái niệm về mảng kết hợp, có các đối tượng
  2. Cách duy nhất để hợp nhất hai đối tượng là lặp cho các thuộc tính của chúng và sao chép các con trỏ vào các giá trị của chúng không phải là kiểu nguyên thủy và giá trị cho kiểu nguyên thủy sang thể hiện khác

8
Các đối tượng trong Javascript được triển khai dưới dạng các mảng kết hợp, do đó chắc chắn có khái niệm tương tự
Dexygen

2

Năm 2019 bạn có 2 lựa chọn tốt:

Phân công đối tượng [ doc ]

const result = Object.assign({}, baseObject, updatingObject);

Đối tượng truyền bá [ doc ]

const result = { ...baseObject, ...updatingObject};

Cái đầu tiên có xu hướng an toàn hơn, chuẩn hơn và đa trị. Một ưu và nhược điểm tốt ở đây



1

jquery có một boolean cho bản sao sâu. Bạn có thể làm một cái gì đó như thế:

MergeRecursive = function(arr1, arr2){
    $.extend(true, arr1, arr2);
    return arr1;                
};

Ngoài ra, bạn có thể chỉnh sửa chức năng này để hỗ trợ n-mảng để hợp nhất.

ArrayMergeRecursive = function(){
     if(arguments.length < 2){
          throw new Error("ArrayMergeRecursive: Please enter two or more objects to merge!");
     }

    var arr1=arguments[0];
    for(var i=0; i<=arguments.length; i++ ){
        $.extend(true, arr1, arguments[i]);                 
    }

    return arr1;                
};

Vì vậy, bây giờ bạn có thể làm

var arr1 = {'color': {'mycolor': 'red'}, 3: 5},
    arr2 = {4: 10, 'color': {'favorite': 'green', 0: 'blue'}},
    arr3 = ['Peter','Jhon','Demosthenes'],
    results = ArrayMergeRecursive(arr1, arr2, arr3); // (arr1, arr2 ... arrN)
console.log("Result is:", results);

0

Tôi cần một sự hợp nhất sâu sắc đối tượng. Vì vậy, tất cả các câu trả lời khác không giúp tôi rất nhiều. _.extend và jQuery.extend làm tốt, trừ khi bạn có một mảng đệ quy như tôi làm. Nhưng nó không tệ lắm, bạn có thể lập trình nó trong năm phút:

var deep_merge = function (arr1, arr2) {
    jQuery.each(arr2, function (index, element) {
        if (typeof arr1[index] === "object" && typeof element === "object") {
            arr1[index] = deep_merge(arr1[index], element);
        } else if (typeof arr1[index] === "array" && typeof element === "array") {
            arr1[index] = arr1[index].concat(element);
        } else {
            arr1[index] = element;
        }
    });
    return arr1;
}

0

Để hợp nhất các mảng trong jQuery, còn $ .merge thì sao?

var merged = $.merge([{id:3, value:'foo3'}], [{id:1, value:'foo1'}, {id:2, value:'foo2'}]);
merged[0].id == 3;
merged[0].value == 'foo3';
merged[1].id == 1;
merged[1].value == 'foo1';
merged[2].id == 2;
merged[2].value == 'foo2';

0

Giải pháp đệ quy (mở rộng cả mảng của các đối tượng) + null đã kiểm tra

var addProps = function (original, props) {
    if(!props) {
        return original;
    }
    if (Array.isArray(original)) {
        original.map(function (e) {
            return addProps(e, props)
        });
        return original;
    }
    if (!original) {
        original = {};
    }
    for (var property in props) {
        if (props.hasOwnProperty(property)) {
            original[property] = props[property];
        }
    }
    return original;
};

Xét nghiệm

console.log(addProps([{a: 2}, {z: 'ciao'}], {timestamp: 13}));
console.log(addProps({single: true}, {timestamp: 13}));
console.log(addProps({}, {timestamp: 13}));
console.log(addProps(null, {timestamp: 13}));

[ { a: 2, timestamp: 13 }, { z: 'ciao', timestamp: 13 } ]
{ single: true, timestamp: 13 }
{ timestamp: 13 }
{ timestamp: 13 }

Tôi đã thử sử dụng cái này với Node JS, nhưng Object.getOwnPropertyNames is not a functionsẽ làm hỏng ứng dụng.
Legoless

Tôi đang sử dụng công cụ này với một số công cụ v8 cũ trong phần mở rộng Plv8 PostgreSQL. Và nó hoạt động trong trình duyệt. Chỉ cần tìm một cách trong công cụ JS của bạn để làm điều tương tự là "hasOwnProperty". Sau đó, bạn có thể sử dụng lại logic này.
sscarduzio 17/05/2016

0

Đây là giải pháp tốt nhất.

obj1.unshift.apply( obj1, obj2 );

Ngoài ra, obj1có thể phát triển bên trong một vòng lặp mà không có bất kỳ vấn đề. (giả sử obj2là động)

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.