不使用 jQuery 在 node.js 上组合或合并 JSON

我有多个这样的 JSON

var object1 = {name: "John"};
var object2 = {location: "San Jose"};

它们没有筑巢之类的。只是基本上不同的领域。我需要在 Node Js中将它们组合成一个单独的 JSON,像这样:

{name: "John", location: "San Jose"}

我可以很好地使用 JQuery,下面是浏览器中的一个工作示例:

Http://jsfiddle.net/qhoc/agp54/

但是如果我在 Node Js中这样做,我不想加载 jQuery (这有点过度使用,而且 Js 的 jQuery不能在我的 窗户机器上工作)。

那么,是否有一种简单的方法来做类似于没有 JQuery$.extend()的事情呢?

168044 次浏览

A normal loop?

function extend(target) {
var sources = [].slice.call(arguments, 1);
sources.forEach(function (source) {
for (var prop in source) {
target[prop] = source[prop];
}
});
return target;
}


var object3 = extend({}, object1, object2);

That's a basic starting point. You may want to add things like a hasOwnProperty check, or add some logic to handle the case where multiple source objects have a property with the same identifier.

Here's a working example.

Side note: what you are referring to as "JSON" are actually normal JavaScript objects. JSON is simply a text format that shares some syntax with JavaScript.

Underscore's extend is the easiest and quickest way to achieve this, like James commented.

Here's an example using underscore:

var _ = require('underscore'), // npm install underscore to install
object1 = {name: "John"},
object2 = {location: "San Jose"};


var target = _.extend(object1, object2);

object 1 will get the properties of object2 and be returned and assigned to target. You could do it like this as well, depending on whether you mind object1 being modified:

var target = {};
_.extend(target, object1, object2);

Here is simple solution, to merge JSON. I did the following.

  • Convert each of the JSON to strings using JSON.stringify(object).
  • Concatenate all the JSON strings using + operator.
  • Replace the pattern /}{/g with ","
  • Parse the result string back to JSON object

    var object1 = {name: "John"};
    var object2 = {location: "San Jose"};
    var merged_object = JSON.parse((JSON.stringify(object1) + JSON.stringify(object2)).replace(/}{/g,","))
    

The resulting merged JSON will be

{name: "John", location: "San Jose"}

I see that this thread is too old, but I put my answer here just in logging purposes.

In one of the comments above you mentioned that you wanted to use 'express' in your project which has 'connect' library in the dependency list. Actually 'connect.utils' library contains a 'merge' method that does the trick. So you can use the 3rd party implementation without adding any new 3rd party libraries.

Use merge.

$ npm install merge

Sample code:

var merge = require('merge'), // npm install -g merge
original, cloned;


console.log(


merge({ one: 'hello' }, { two: 'world' })


); // {"one": "hello", "two": "world"}


original = { x: { y: 1 } };


cloned = merge(true, original);


cloned.x.y++;


console.log(original.x.y, cloned.x.y); // 1, 2

If using Node version >= 4, use Object.assign() (see Ricardo Nolde's answer).

If using Node 0.x, there is the built in util._extend:

var extend = require('util')._extend
var o = extend({}, {name: "John"});
extend(o,  {location: "San Jose"});

It doesn't do a deep copy and only allows two arguments at a time, but is built in. I saw this mentioned on a question about cloning objects in node: https://stackoverflow.com/a/15040626.

If you're concerned about using a "private" method, you could always proxy it:

// myutil.js
exports.extend = require('util')._extend;

and replace it with your own implementation if it ever disappears. This is (approximately) their implementation:

exports.extend = function(origin, add) {
if (!add || (typeof add !== 'object' && add !== null)){
return origin;
}


var keys = Object.keys(add);
var i = keys.length;
while(i--){
origin[keys[i]] = add[keys[i]];
}
return origin;
};

The below code will help you to merge two JSON object which has nested objects.

function mergeJSON(source1,source2){
/*
* Properties from the Souce1 object will be copied to Source2 Object.
* Note: This method will return a new merged object, Source1 and Source2 original values will not be replaced.
* */
var mergedJSON = Object.create(source2);// Copying Source2 to a new Object


for (var attrname in source1) {
if(mergedJSON.hasOwnProperty(attrname)) {
if ( source1[attrname]!=null && source1[attrname].constructor==Object ) {
/*
* Recursive call if the property is an object,
* Iterate the object and set all properties of the inner object.
*/
mergedJSON[attrname] = zrd3.utils.mergeJSON(source1[attrname], mergedJSON[attrname]);
}


} else {//else copy the property from source1
mergedJSON[attrname] = source1[attrname];


}
}


return mergedJSON;
}

If you need special behaviors like nested object extension or array replacement you can use Node.js's extendify.

var extendify = require('extendify');


_.extend = extendify({
inPlace: false,
arrays : 'replace',
isDeep: true
});


obj1 = {
a:{
arr: [1,2]
},
b: 4
};


obj2 = {
a:{
arr: [3]
}
};


res = _.extend(obj1,obj2);
console.log(JSON.stringify(res)); //{'a':{'arr':[3]},'b':4}

You can also use this lightweight npm package called absorb

It is 27 lines of code, 1kb and uses recursion to perform deep object merges.

var absorb = require('absorb');
var obj1, obj2;


obj1 = { foo: 123, bar: 456 };
obj2 = { bar: 123, key: 'value' }


absorb(obj1, obj2);


console.log(obj1); // Output: { foo: 123, bar: 123, key: 'value' }

You can also use it to make a clone or only transfer values if they don't exist in the source object, how to do this is detailed in the link provided.

You should use "Object.assign()"

There's no need to reinvent the wheel for such a simple use case of shallow merging.

The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.

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
console.log(obj === o1) // true

Even the folks from Node.js say so:

_extend was never intended to be used outside of internal NodeJS modules. The community found and used it anyway. It is deprecated and should not be used in new code. JavaScript comes with very similar built-in functionality through Object.assign.


Update:

You could use the spread operator

Since version 8.6, it's possible to natively use the spread operator in Node.js. Example below:

let o1 = { a: 1 };
let o2 = { b: 2 };
let obj = { ...o1, ...o2 }; // { a: 1, b: 2 }

Object.assign still works, though.


**PS1**: If you are actually interested in **deep merging** (in which internal object data -- in any depth -- is recursively merged), you can use packages like [deepmerge][4], [assign-deep][5] or [lodash.merge][6], which are pretty small and simple to use. **PS2**: Keep in mind that **Object.assign doesn't work with 0.X versions of Node.js**. If you are working with one of those versions (_you really shouldn't by now_), you could use `require("util")._extend` as shown in the Node.js link above -- for more details, check [tobymackenzie's answer to this same question](https://stackoverflow.com/a/22286375/36272).

Let object1 and object2 be two JSON object.

var object1 = [{"name": "John"}];
var object2 = [{"location": "San Jose"}];


object1.push(object2);

This will simply append object2 in object1:

[{"name":"John"},{"location":"San Jose"}]

Lodash is a another powerful tool-belt option for these sorts of utilities. See: _.merge() (which is recursive)

var object = {
'a': [{ 'b': 2 }, { 'd': 4 }]
};
var other = {
'a': [{ 'c': 3 }, { 'e': 5 }]
};
_.merge(object, other);
// => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }

It can easy be done using Object.assign() method -

 var object1 = {name: "John"};
var object2 = {location: "San Jose"};
var object3 = Object.assign(object1,object2);
console.log(object3);

now object3 is { name: 'John', location: 'San Jose' }

You can use Lodash

const _ = require('lodash');


let firstObject = {'email' : 'email@email.com};
let secondObject = { 'name' : { 'first':message.firstName } };
_.merge(firstObject, secondObject)

A better approach from the correct solution here in order to not alter target:

function extend(){
let sources = [].slice.call(arguments, 0), result = {};
sources.forEach(function (source) {
for (let prop in source) {
result[prop] = source[prop];
}
});
return result;
}

There is an easy way of doing it in Node.js

var object1 = {name: "John"};
var object2 = {location: "San Jose"};

To combine/extend this we can use ... operator in ECMA6

var object1 = {name: "John"};
var object2 = {location: "San Jose"};


var result = {
...object1,
...object2
}


console.log(result)

You can do it inline, without changing any variables like this:

let obj1 = { name: 'John' };
let obj2 = { surname: 'Smith' };
let obj = Object.assign({}, obj1, obj2); // { name: 'John', surname: 'Smith' }

Use spread operator. It is supported in Node since version 8.6

const object1 = {name: "John"};
const object2 = {location: "San Jose"};


const obj = {...object1, ...object2}


console.log(obj)
//   {
//     "name": "John",
//     "location": "San Jose"
//   }