Как динамически объединить свойства двух объектов JavaScript? - PullRequest
2173 голосов
/ 05 октября 2008

Мне нужно иметь возможность объединять два (очень простых) объекта JavaScript во время выполнения. Например, я хотел бы:

var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }

obj1.merge(obj2);

//obj1 now has three properties: food, car, and animal

Кто-нибудь имеет сценарий для этого или знает встроенный способ сделать это? Мне не нужна рекурсия, и мне не нужно объединять функции, только методы для плоских объектов.

Ответы [ 60 ]

33 голосов
/ 30 января 2015

Следующие два, вероятно, являются хорошей отправной точкой. У lodash также есть функция настройки для этих особых нужд!

_.extend (http://underscorejs.org/#extend)
_.merge (https://lodash.com/docs#merge)

27 голосов
/ 19 сентября 2012

Кстати, все, что вы делаете - перезаписываете свойства, а не объединяете ...

Вот как действительно объединилась область объектов JavaScript: только ключи в объекте to, которые не являются самими объектами, будут перезаписаны from. Все остальное будет действительно объединено . Конечно, вы можете изменить это поведение, чтобы не перезаписывать все, что существует, например, если to[n] is undefined и т. Д ...:

var realMerge = function (to, from) {

    for (n in from) {

        if (typeof to[n] != 'object') {
            to[n] = from[n];
        } else if (typeof from[n] == 'object') {
            to[n] = realMerge(to[n], from[n]);
        }
    }
    return to;
};

Использование:

var merged = realMerge(obj1, obj2);
24 голосов
/ 24 апреля 2013

Вот мой удар, который

  1. Поддерживает глубокое слияние
  2. Не изменяет аргументы
  3. Принимает любое количество аргументов
  4. Не расширяет прототип объекта
  5. Не зависит от другой библиотеки ( jQuery , MooTools , Underscore.js и т. Д.)
  6. Включает проверку на hasOwnProperty
  7. Коротко:)

    /*
        Recursively merge properties and return new object
        obj1 <- obj2 [ <- ... ]
    */
    function merge () {
        var dst = {}
            ,src
            ,p
            ,args = [].splice.call(arguments, 0)
        ;
    
        while (args.length > 0) {
            src = args.splice(0, 1)[0];
            if (toString.call(src) == '[object Object]') {
                for (p in src) {
                    if (src.hasOwnProperty(p)) {
                        if (toString.call(src[p]) == '[object Object]') {
                            dst[p] = merge(dst[p] || {}, src[p]);
                        } else {
                            dst[p] = src[p];
                        }
                    }
                }
            }
        }
    
       return dst;
    }
    

Пример: * * тысяча двадцать-восемь

a = {
    "p1": "p1a",
    "p2": [
        "a",
        "b",
        "c"
    ],
    "p3": true,
    "p5": null,
    "p6": {
        "p61": "p61a",
        "p62": "p62a",
        "p63": [
            "aa",
            "bb",
            "cc"
        ],
        "p64": {
            "p641": "p641a"
        }
    }
};

b = {
    "p1": "p1b",
    "p2": [
        "d",
        "e",
        "f"
    ],
    "p3": false,
    "p4": true,
    "p6": {
        "p61": "p61b",
        "p64": {
            "p642": "p642b"
        }
    }
};

c = {
    "p1": "p1c",
    "p3": null,
    "p6": {
        "p62": "p62c",
        "p64": {
            "p643": "p641c"
        }
    }
};

d = merge(a, b, c);


/*
    d = {
        "p1": "p1c",
        "p2": [
            "d",
            "e",
            "f"
        ],
        "p3": null,
        "p5": null,
        "p6": {
            "p61": "p61b",
            "p62": "p62c",
            "p63": [
                "aa",
                "bb",
                "cc"
            ],
            "p64": {
                "p641": "p641a",
                "p642": "p642b",
                "p643": "p641c"
            }
        },
        "p4": true
    };
*/
18 голосов
/ 26 февраля 2010

Для не слишком сложных объектов вы можете использовать JSON :

var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog', car: 'chevy'}
var objMerge;

objMerge = JSON.stringify(obj1) + JSON.stringify(obj2);

// {"food": "pizza","car":"ford"}{"animal":"dog","car":"chevy"}

objMerge = objMerge.replace(/\}\{/, ","); //  \_ replace with comma for valid JSON

objMerge = JSON.parse(objMerge); // { food: 'pizza', animal: 'dog', car: 'chevy'}
// Of same keys in both objects, the last object's value is retained_/

Имейте в виду, что в этом примере "} {" не должно встречаться внутри строки!

18 голосов
/ 16 ноября 2015

Object.assign ()

ECMAScript 2015 (ES6)

Это новая технология, часть стандарта ECMAScript 2015 (ES6). Спецификация этой технологии была доработана, но проверьте таблицу совместимости на предмет использования и состояния реализации в различных браузерах.

Метод 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 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, target object itself is changed.
16 голосов
/ 10 ноября 2010

Лучший способ сделать это - добавить правильное свойство, которое нельзя перечислить, используя Object.defineProperty.

Таким образом, вы все равно сможете перебирать свойства ваших объектов, не имея вновь созданного «расширения», которое вы получите, если бы вы создали свойство с Object.prototype.extend.

Надеюсь, это поможет:

Object.defineProperty(Object.prototype, "extend", {
    enumerable: false,
    value: function(from) {
        var props = Object.getOwnPropertyNames(from);
        var dest = this;
        props.forEach(function(name) {
            if (name in dest) {
                var destination = Object.getOwnPropertyDescriptor(from, name);
                Object.defineProperty(dest, name, destination);
            }
        });
        return this;
    }
});

Как только у вас будет эта работа, вы можете сделать:

var obj = {
    name: 'stack',
    finish: 'overflow'
}
var replacement = {
    name: 'stock'
};

obj.extend(replacement);

Я только что написал пост в блоге об этом здесь: http://onemoredigit.com/post/1527191998/extending-objects-in-node-js

15 голосов
/ 23 июня 2014

Есть библиотека с именем deepmerge на GitHub : Кажется, что это набирает силу. Это автономная версия, доступная как через npm , так и через менеджеров пакетов bower.

Я был бы склонен использовать или улучшать это вместо того, чтобы копировать код из ответов.

15 голосов
/ 31 августа 2015

Вы можете просто использовать jQuery extend

var obj1 = { val1: false, limit: 5, name: "foo" };
var obj2 = { val2: true, name: "bar" };

jQuery.extend(obj1, obj2);

Теперь obj1 содержит все значения obj1 и obj2

12 голосов
/ 05 октября 2008

Прототип имеет это:

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

obj1.extend(obj2) будет делать то, что вы хотите.

11 голосов
/ 20 апреля 2012

Просто, если кто-то использует Google Closure Library :

goog.require('goog.object');
var a = {'a': 1, 'b': 2};
var b = {'b': 3, 'c': 4};
goog.object.extend(a, b);
// Now object a == {'a': 1, 'b': 3, 'c': 4};

Аналогичная вспомогательная функция существует для массива :

var a = [1, 2];
var b = [3, 4];
goog.array.extend(a, b); // Extends array 'a'
goog.array.concat(a, b); // Returns concatenation of array 'a' and 'b'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...