Об’єднання об'єктів (асоціативні масиви)


147

Який найкращий / стандартний спосіб об’єднання двох асоціативних масивів у JavaScript? Чи всі це роблять, прокручуючи власну forпетлю?


10
в javascript btw немає асоціативних масивів, лише об'єкти.
— gblazex

CrossRef ж питання в Perl: stackoverflow.com/questions/350018 / ...
— dreftymac

Асоціативні масиви у javascript: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
— Кріс Мартін

Відповіді:


204

за допомогою jquery ви можете зателефонувати $.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

(допоміжні масиви - це об'єкти в js)

дивіться тут: http://api.jquery.com/jQuery.extend/


редагувати: Як запропонував rymo, краще зробити це так:

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

Оскільки тут obj1 (і obj2) залишаються незмінними.


edit2: У 2018 році спосіб зробити це через Object.assign:

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

Якщо працювати з ES6, цього можна досягти за допомогою оператора Spread :

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

54
або щоб уникнути глузування obj1, використовуйте порожній об’єкт як ціль:$.extend({}, obj1, obj2)
— rymo

Так, під час роботи із закриттями та об'єктами, переданими посиланням, дотримуйтесь порад римо, щоб не впливати на оригінальний об'єкт для наступних операцій.
— Натан Сміт

2
Для сучасних веб-переглядачів перевірте рішення за допомогою @manfred Object.assign(), яке не покладається на JQuery, якщо ви вже не використовуєте бібліотеку.
— Філ

Це працює, але він змінює перший параметр, і це те, що вам потрібно знати. Дивіться developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
— kulpae

62

Зараз у 2016 році я б сказав, що найкращий / стандартний спосіб - Object.assign ()
Чистий Javascript. Не потрібен jQuery.

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

Більше інформації, приклади та полізаповнення тут:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign


Який тип obj3? що якщо obj1 - це тип IABC, буде obj3 зберегти цей тип після цього?
— windmaomao

49

Ось як це робить прототип:

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

називається як, наприклад:

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

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

EDIT : додано перевірку hasOwnProperty (), як правильно вказав bucabay в коментарях


6
Вам знадобиться тестовий source.hasOwnProperty (властивість), щоб переконатися, що ви копіюєте лише безпосередні властивості. Так, це може скопіювати всі властивості, включаючи ті, що походять від Object.prototype
— bucabay

22

Не ускладнювати...

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

6
Ви повинні перевірити hasOwnProperty, щоб уникнути копіювання будь-яких властивостей наarrau1.prototype
— LeeGee

@LeeGee має рацію. Вам потрібна ця hasOwnPropertyперевірка. Посилання на об'єкти як масиви також вводить в оману (вони є об'єктами), назви аргументів повинні свідчити про те, що array2 мутується або новий об’єкт повинен бути повернутий. Я би відредагував відповідь, але фактично це стане майже точно відредагованою відповіддю Джонатана Фінгленда, яка вже виправлена.
— Ваз

14

Підкреслення також має метод розширення:

Скопіюйте всі властивості вихідних об'єктів на об'єкт призначення. Це в порядку, тож останнє джерело буде заміняти однойменні властивості в попередніх аргументах.

_.extend(destination, *sources) 

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


6

чи хочете ви перезаписати властивість, якщо імена однакові, але значення немає?

І чи хочете ви назавжди змінити один з оригінальних об'єктів,

чи ви хочете повернути новий об'єднаний об’єкт?

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

Рухомий свої власні Extend / підмішати функції

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???' });

...

Це просто розширює сплеск предметів, рекурсивно. Також зауважте, що ця рекурсивна функція є TCO ( Tail-Call Optimized ), оскільки її повернення є останнім викликом до себе.

Крім того, ви можете захопити цільові властивості . У цьому випадку ви можете конденсувати об'єкти на основі id,quantity або інше майно. Цей підхід може писати про це невелику книгу, яка вимагає об'єктної супозиції та може отримати дуже складний характер. Я написав для цього невелику бібліотеку, яка доступна за запитом.

Сподіваюся, це допомагає!


4
  1. У Javascript немає поняття асоціативного масиву, є об'єкти
  2. Єдиний спосіб об'єднання двох об'єктів - це пошук циклу на їх властивості та копіювання покажчиків на їх значення, які не є примітивними типами та значеннями для примітивних типів в інший екземпляр

8
Об'єкти в Javascript реалізовані як асоціативні масиви, тому, безумовно, існує поняття того ж
— Dexygen

2

У 2019 році у вас є 2 хороших варіанти:

Призначення об’єкта [ doc ]

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

Поширення об’єктів [ doc ]

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

Перший має тенденцію бути більш безпечним, стандартним та багатовалентним. Хороші плюси і мінуси тут



1

jquery має булеву форму для глибокої копії. Ви можете зробити щось подібне:

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

Також ви можете редагувати цю функцію для підтримки n-масивів для злиття.

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;                
};

Так що тепер ви можете зробити

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

Мені було потрібно об'єднання глибоких об'єктів. Тож усі інші відповіді мені не дуже допомогли. _.extend і jQuery.extend справляються добре, якщо тільки у вас немає рекурсивного масиву, як я. Але це не так вже й погано, ви можете запрограмувати його на п’ять хвилин:

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

Щоб об'єднати масиви в jQuery, що з $ .merge?

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

Рекурсивне рішення (розширює також масиви об’єктів) + перевірено нуль

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;
};

Тести

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 }

Я спробував це використати разом із Node JS, але Object.getOwnPropertyNames is not a functionдодаток перестане працювати.
— Безголосий

Я використовую це за допомогою старовинного двигуна v8 в межах розширення plv8 PostgreSQL. І це працює в браузерах. Просто знайдіть у своєму двигуні JS спосіб зробити еквівалентну річ, як "hasOwnProperty". Тоді ви можете повторно використовувати цю логіку.
— sscarduzio

0

Ось найкраще рішення.

obj1.unshift.apply( obj1, obj2 );

Також obj1може рости всередині циклу без проблем. (скажімо, obj2це динамічно)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.