A more aesthetic way of copying an object literal? - javascript

This is client side. Webpack, Babel and Babel Imports.
My project has a folder called "models" which contains object literals as definitions of the expected JSON results from endpoints.
The objects only contain strings, ints, booleans and arrays/objects which contain those data types
eg:
{
name: "String"
age: 35,
active: true,
permissions: [
{ news: true }
]
}
When I want to use a model definition, in order to ensure I don't have issues with references, I must use:
let newObject1 = Object.assign({}, originalObj )
or
let newObject2 = JSON.parse( JSON.stringify( originalObj ))
I find this a bit ugly and it pollutes my code a bit.
I would love the ability to use the new keyword on object literals, but of course that's not a thing.
let clone = new targetObj
What's the most aesthetic way to handle the cloning of an object literal without creating a reference?

The JavaScript way of implementing such object "templates" are constructors:
function Original() {
this.name = "String";
this.age = 18;
this.active = true;
this.permissions = [
{ news: true }
];
}
var obj = new Original();
console.log(obj);
Or, in ES6 class syntax:
class Original {
constructor() {
this.name = "String";
this.age = 18;
this.active = true;
this.permissions = [
{ news: true }
];
}
}
let obj = new Original();
console.log(obj);
Be aware that Object.assign will only create a shallow copy, so it would not copy the permissions array, but provide a reference to the same array as in the original object.
const originalObject = {
name: "String",
age: 35,
active: true,
permissions: [
{ news: true }
]
};
let obj1 = Object.assign({}, originalObject);
let obj2 = Object.assign({}, originalObject);
// change a permission:
obj1.permissions[0].news = false;
// See what permissions are in obj2:
console.log(obj1.permissions);

const model = () => ({
name: 'string',
age: 20,
array: [ 1, 2, 3 ]
});
let newObject = model();
You won't have the pleasure of using new - see trincot's answer for that - but you don't have to worry about nested objects (assign) or feel gross (stringify + parse).

Related

can't use "this" on both sides of assignment

I want to make my function addHat() reusable for other person objects as well, so I decided to use this instead of exact name of the person and pass my other objects as this by addHat.call() and addHat.apply() methods.
ie. I want to shallow copy the person object using spread (having new references for all of the properties.
However, it doesn't work using this on both sides of the assignment
let person1 = {
a: "a",
hats: [],
gloves: []
};
function addHat(newHat, ...params) {
this = {
...this,
hats: [...this.hats, newHat, ...params],
};
}
addHat.call(person1, "hatA");
console.log(person1.hats);
But perfectly works when using the name directly instead:
let person1 = {
a: "a",
hats: [],
gloves: []
};
function addHat(newHat, ...params) {
person1 = {
...person1,
hats: [...person1.hats, newHat, ...params],
};
}
addHat.apply("uselessThis", ["hatA", "hatB"]);
console.log(person1.hats);
Can you help me to make this function reusable with the current format? (using spread and shallow copying of the object properties)
every hint or help will be much appreciated.
I think that it's easier if you pass persona as an argument of the function.
Try to avoid the use of this in js because it can become tricky to debug
let person1 = {
a: "a",
hats: [],
gloves: []
};
function immutableAddHat(person, ...newHats) {
return {
...person,
hats: [...person.hats, ...newHats],
};
}
function addHat(...newHats) {
Object.entries(this).forEach(([k, v]) => {
this[k] = v
})
this.hats = [...this.hats, ...newHats]
}
const newPerson1 = immutableAddHat(person1, "hatA");
console.log(newPerson1.hats);
addHat.call(person1, "Hatb")
console.log(person1)
I added the method that uses this

Modify JS Object in Pure Way

I have a function that transforms a JS object. It derives a new property from an existing one, then deletes the original property. Essentially something like this:
/** Derives "capName" property from "name" property, then deletes "name" */
function transform(person) {
person["capName"] = person["name"].toUpperCase();
delete person["name"];
return person;
}
var myPerson = {
name: "Joe",
age: 20
};
var newPerson = transform(myPerson);
console.log(myPerson, newPerson);
The function returns the desired newPerson object, but also modifies the original myPerson object. I would rather do this in a pure way, that doesn't modify the original myPerson object.
Note: I really need to be ES5 compatible, but I'd like to see the ES6 solution as well.
Quite easy with destructuring:
const transform = ({ name, ...rest }) => ({ capName: name.toUpperCase(), ...rest });
I really need to be ES5 compatible
Use BabelJS, it makes your life so much eaiser.
just use Object.assign which will create a new object with new reference
function transform(person) {
var obj = Object.assign({}, person);
obj["capName"] = obj["name"].toUpperCase();
delete obj["name"];
return obj;
}
var myPerson = {
name: "Joe",
age: 20
};
var newPerson = transform(myPerson);
console.log('newPerson:', newPerson);
console.log('myPerson:', myPerson);
For ES5 compatibility, you can use JSON.parse(JSON.stringify(person)). Be aware that methods attached to person are lost on the way because they cannot properly be JSON.stringifyed.
/** Derives "capName" property from "name" property, then deletes "name" */
function transform(person) {
var obj = JSON.parse(JSON.stringify(person));
obj["capName"] = obj["name"].toUpperCase();
delete obj["name"];
return obj;
}
var myPerson = {
name: "Joe",
age: 20
};
var newPerson = transform(myPerson);
console.log(myPerson, newPerson);
If you want to retain methods, just iterate over the object keys:
/** Derives "capName" property from "name" property, then deletes "name" */
function transform(person) {
var obj = {};
for (var key in person) {
obj[key] = person[key];
}
obj["capName"] = obj["name"].toUpperCase();
delete obj["name"];
return obj;
}
var myPerson = {
name: "Joe",
age: 20
};
var newPerson = transform(myPerson);
console.log(myPerson, newPerson);
Be aware that none of the methods presented does a deep clone. For that, I'd recommend you use something like lodash's _.clone(obj, { deep: true });
You could generate a new object without the unwanted and a new property.
function transform(person) {
return Object
.keys(person)
.reduce(function (r, k) {
if (k === 'name') {
r.capName = person.name.toUpperCase();
} else {
r[k] = person[k];
}
return r;
}, {});
}
var myPerson = { name: "Joe", age: 20 },
newPerson = transform(myPerson);
console.log(myPerson);
console.log(newPerson);

How to use ES6 Object Spread Operator to assign arguments passed to a function as object properties? [duplicate]

For example if I have two objects:
var foo = {
x: "bar",
y: "baz"
}
and
var oof = {}
and I wanted to transfer the x and y values from foo to oof. Is there a way to do that using the es6 destructuring syntax?
perhaps something like:
oof{x,y} = foo
While ugly and a bit repetitive, you can do
({x: oof.x, y: oof.y} = foo);
which will read the two values of the foo object, and write them to their respective locations on the oof object.
Personally I'd still rather read
oof.x = foo.x;
oof.y = foo.y;
or
['x', 'y'].forEach(prop => oof[prop] = foo[prop]);
though.
IMO this is the easiest way to accomplish what you're looking for:
let { prop1, prop2, prop3 } = someObject;
let data = { prop1, prop2, prop3 };
// data === { prop1: someObject.prop1, ... }
Basically, destructure into variables and then use the initializer shorthand to make a new object. No need for Object.assign
I think this is the most readable way, anyways. You can hereby select the exact props out of someObject that you want. If you have an existing object you just want to merge the props into, do something like this:
let { prop1, prop2, prop3 } = someObject;
let data = Object.assign(otherObject, { prop1, prop2, prop3 });
// Makes a new copy, or...
Object.assign(otherObject, { prop1, prop2, prop3 });
// Merges into otherObject
Another, arguably cleaner, way to write it is:
let { prop1, prop2, prop3 } = someObject;
let newObject = { prop1, prop2, prop3 };
// Merges your selected props into otherObject
Object.assign(otherObject, newObject);
I use this for POST requests a lot where I only need a few pieces of discrete data. But, I agree there should be a one liner for doing this.
EDIT: P.S. -
I recently learned you can use ultra destructuring in the first step to pull nested values out of complex objects! For instance...
let { prop1,
prop2: { somethingDeeper },
prop3: {
nested1: {
nested2
}
} = someObject;
let data = { prop1, somethingDeeper, nested2 };
Plus, you could use spread operator instead of Object.assign when making a new object:
const { prop1, prop2, prop3 } = someObject;
let finalObject = {...otherObject, prop1, prop2, prop3 };
Or...
const { prop1, prop2, prop3 } = someObject;
const intermediateObject = { prop1, prop2, prop3 };
const finalObject = {...otherObject, ...intermediateObject };
No, destructuring does not support member expressions in shorthands but only plain propertynames at the current time. There have been talks about such on esdiscuss, but no proposals will make it into ES6.
You might be able to use Object.assign however - if you don't need all own properties, you still can do
var foo = …,
oof = {};
{
let {x, y} = foo;
Object.assign(oof, {x, y})
}
Other than Object.assign there is the object spread syntax which is a Stage 2 proposal for ECMAScript.
var foo = {
x: "bar",
y: "baz"
}
var oof = { z: "z" }
oof = {...oof, ...foo }
console.log(oof)
/* result
{
"x": "bar",
"y": "baz",
"z": "z"
}
*/
But to use this feature you need to use stage-2 or transform-object-rest-spread plugin for babel. Here is a demo on babel with stage-2
BabelJS plugin
If you are using BabelJS you can now activate my plugin babel-plugin-transform-object-from-destructuring (see npm package for installation and usage).
I had the same issue described in this thread and for me it was very exhausting when you create an object from a destructuring expression, especially when you have to rename, add or remove a property. With this plugin maintaining such scenarios gets much more easier for you.
Object example
let myObject = {
test1: "stringTest1",
test2: "stringTest2",
test3: "stringTest3"
};
let { test1, test3 } = myObject,
myTest = { test1, test3 };
can be written as:
let myTest = { test1, test3 } = myObject;
Array example
let myArray = ["stringTest1", "stringTest2", "stringTest3"];
let [ test1, , test3 ] = myArray,
myTest = [ test1, test3 ];
can be written as:
let myTest = [ test1, , test3 ] = myArray;
It's totally possible. Just not in one statement.
var foo = {
x: "bar",
y: "baz"
};
var oof = {};
({x: oof.x, y: oof.y} = foo); // {x: "bar", y: "baz"}
(Do note the parenthesis around the statement.)
But keep in mind legibility is more important than code-golfing :).
Source: http://exploringjs.com/es6/ch_destructuring.html#sec_assignment-targets
You can just use restructuring for that like this:
const foo = {x:"a", y:"b"};
const {...oof} = foo; // {x:"a", y:"b"}
Or merge both objects if oof has values:
const foo = {x:"a", y:"b"};
let oof = {z:"c"}
oof = Object.assign({}, oof, foo)
You can return the destructured object in an arrow function, and use Object.assign() to assign it to a variable.
const foo = {
x: "bar",
y: "baz"
}
const oof = Object.assign({}, () => ({ x, y } = foo));
You can destruct an object assigning directly to another object attribute.
Working example:
let user = {};
[user.name, user.username] = "Stack Overflow".split(' ');
document.write(`
1st attr: ${user.name} <br />
2nd attr: ${user.username}`);
You can work with destructing using variables with the same name of object attribute you want to catch, this way you don't need to do:
let user = { name: 'Mike' }
let { name: name } = user;
Use this way:
let user = { name: 'Mike' }
let { name } = user;
The same way you can set new values to object structures if they have the same attribute name.
Look this working example:
// The object to be destructed
let options = {
title: "Menu",
width: 100,
height: 200
};
// Destructing
let {width: w, height: h, title} = options;
// Feedback
document.write(title + "<br />"); // Menu
document.write(w + "<br />"); // 100
document.write(h); // 200
Try
var a = {a1:1, a2: 2, a3: 3};
var b = {b1:1, b2: 2, b3: 3};
const newVar = (() => ({a1, a2, b1, b2})).bind({...a, ...b});
const val = newVar();
console.log({...val});
// print: Object { a1: 1, a2: 2, b1: 1, b2: 2 }
or
console.log({...(() => ({a1, a2, b1, b2})).bind({...a, ...b})()});
I came up with this method:
exports.pick = function pick(src, props, dest={}) {
return Object.keys(props).reduce((d,p) => {
if(typeof props[p] === 'string') {
d[props[p]] = src[p];
} else if(props[p]) {
d[p] = src[p];
}
return d;
},dest);
};
Which you can use like this:
let cbEvents = util.pick(this.props.events, {onFocus:1,onBlur:1,onCheck:'onChange'});
let wrapEvents = util.pick(this.props.events, {onMouseEnter:1,onMouseLeave:1});
i.e., you can pick which properties you want out and put them into a new object. Unlike _.pick you can also rename them at the same time.
If you want to copy the props onto an existing object, just set the dest arg.
This is kind of cheating, but you can do something like this...
const originalObject = {
hello: 'nurse',
meaningOfLife: 42,
your: 'mom',
};
const partialObject = (({ hello, your }) => {
return { hello, your };
})(originalObject);
console.log(partialObject); // ​​​​​{ hello: 'nurse', your: 'mom' }​​​​​
In practice, I think you'd rarely want to use that though. The following is MUCH more clear... but not nearly as fun.
const partialObject = {
hello: originalObject.hello,
your: originalObject.your,
};
Another completely different route, which includes mucking with the prototype (careful now...):
if (!Object.prototype.pluck) {
Object.prototype.pluck = function(...props) {
return props.reduce((destObj, prop) => {
destObj[prop] = this[prop];
return destObj;
}, {});
}
}
const originalObject = {
hello: 'nurse',
meaningOfLife: 42,
your: 'mom',
};
const partialObject2 = originalObject.pluck('hello', 'your');
console.log(partialObject2); // { hello: 'nurse', your: 'mom' }
This is the most readable and shortest solution I could come up with:
let props = {
isValidDate: 'yes',
badProp: 'no!',
};
let { isValidDate } = props;
let newProps = { isValidDate };
console.log(newProps);
It will output { isValidDate: 'yes' }
It would be nice to some day be able to say something like let newProps = ({ isValidDate } = props) but unfortunately it is not something ES6 supports.
You can use JSON class methods to achieve it as follows
const foo = {
x: "bar",
y: "baz"
};
const oof = JSON.parse(JSON.stringify(foo, ['x','y']));
// output -> {x: "bar", y: "baz"}
Pass properties that need to be added to the resulting object as second argument to stringify function in an array format.
MDN Doc for JSON.stringify
This works in chrome 53.0.2785.89
let foo = {
x: "bar",
y: "baz"
};
let oof = {x, y} = foo;
console.log(`oof: ${JSON.stringify(oof)}`);
//prints oof: { "x": "bar", "y": "baz"}
It's not a beautiful way, nor I recommend it, but it's possible this way, just for knowledge.
const myObject = {
name: 'foo',
surname: 'bar',
year: 2018
};
const newObject = ['name', 'surname'].reduce(
(prev, curr) => (prev[curr] = myObject[curr], prev),
{},
);
console.log(JSON.stringify(newObject)); // {"name":"foo","surname":"bar"}

Remove value from object without mutation

What's a good and short way to remove a value from an object at a specific key without mutating the original object?
I'd like to do something like:
let o = {firstname: 'Jane', lastname: 'Doe'};
let o2 = doSomething(o, 'lastname');
console.log(o.lastname); // 'Doe'
console.log(o2.lastname); // undefined
I know there are a lot of immutability libraries for such tasks, but I'd like to get away without a library. But to do this, a requirement would be to have an easy and short way that can be used throughout the code, without abstracting the method away as a utility function.
E.g. for adding a value I do the following:
let o2 = {...o1, age: 31};
This is quite short, easy to remember and doesn't need a utility function.
Is there something like this for removing a value? ES6 is very welcome.
Thank you very much!
Update:
You could remove a property from an object with a tricky Destructuring assignment:
const doSomething = (obj, prop) => {
let {[prop]: omit, ...res} = obj
return res
}
Though, if property name you want to remove is static, then you could remove it with a simple one-liner:
let {lastname, ...o2} = o
The easiest way is simply to Or you could clone your object before mutating it:
const doSomething = (obj, prop) => {
let res = Object.assign({}, obj)
delete res[prop]
return res
}
Alternatively you could use omit function from lodash utility library:
let o2 = _.omit(o, 'lastname')
It's available as a part of lodash package, or as a standalone lodash.omit package.
With ES7 object destructuring:
const myObject = {
a: 1,
b: 2,
c: 3
};
const { a, ...noA } = myObject;
console.log(noA); // => { b: 2, c: 3 }
one line solution
const removeKey = (key, {[key]: _, ...rest}) => rest;
Explanations:
This is a generic arrow function to remove a specific key. The first argument is the name of the key to remove, the second is the object from where you want to remove the key. Note that by restructuring it, we generate the curated result, then return it.
Example:
let example = {
first:"frefrze",
second:"gergerge",
third: "gfgfg"
}
console.log(removeKey('third', example))
/*
Object {
first: "frefrze",
second: "gergerge"
}
*/
To add some spice bringing in Performance. Check this thread bellow
https://github.com/googleapis/google-api-nodejs-client/issues/375
The use of the delete operator has performance negative effects for
the V8 hidden classes pattern. In general it's recommended do not use
it.
Alternatively, to remove object own enumerable properties, we could
create a new object copy without those properties (example using
lodash):
_.omit(o, 'prop', 'prop2')
Or even define the property value to null or undefined (which is
implicitly ignored when serializing to JSON):
o.prop = undefined
You can use too the destructing way
const {remov1, remov2, ...new} = old;
old = new;
And a more practical exmple:
this._volumes[this._minCandle] = undefined;
{
const {[this._minCandle]: remove, ...rest} = this._volumes;
this._volumes = rest;
}
As you can see you can use [somePropsVarForDynamicName]: scopeVarName syntax for dynamic names. And you can put all in brackets (new block) so the rest will be garbage collected after it.
Here a test:
exec:
Or we can go with some function like
function deleteProps(obj, props) {
if (!Array.isArray(props)) props = [props];
return Object.keys(obj).reduce((newObj, prop) => {
if (!props.includes(prop)) {
newObj[prop] = obj[prop];
}
return newObj;
}, {});
}
for typescript
function deleteProps(obj: Object, props: string[]) {
if (!Array.isArray(props)) props = [props];
return Object.keys(obj).reduce((newObj, prop) => {
if (!props.includes(prop)) {
newObj[prop] = obj[prop];
}
return newObj;
}, {});
}
Usage:
let a = {propH: 'hi', propB: 'bye', propO: 'ok'};
a = deleteProps(a, 'propB');
// or
a = deleteProps(a, ['propB', 'propO']);
This way a new object is created. And the fast property of the object is kept. Which can be important or matter. If the mapping and the object will be accessed many many times.
Also associating undefined can be a good way to go with. When you can afford it. And for the keys you can too check the value. For instance to get all the active keys you do something like:
const allActiveKeys = Object.keys(myObj).filter(k => myObj[k] !== undefined);
//or
const allActiveKeys = Object.keys(myObj).filter(k => myObj[k]); // if any false evaluated value is to be stripped.
Undefined is not suited though for big list. Or development over time with many props to come in. As the memory usage will keep growing and will never get cleaned. So it depend on the usage. And just creating a new object seem to be the good way.
Then the Premature optimization is the root of all evil will kick in. So you need to be aware of the trade off. And what is needed and what's not.
Note about _.omit() from lodash
It's removed from version 5. You can't find it in the repo. And here an issue that talk about it.
https://github.com/lodash/lodash/issues/2930
v8
You can check this which is a good reading https://v8.dev/blog/fast-properties
As suggested in the comments above if you want to extend this to remove more than one item from your object I like to use filter. and reduce
eg
const o = {
"firstname": "Jane",
"lastname": "Doe",
"middlename": "Kate",
"age": 23,
"_id": "599ad9f8ebe5183011f70835",
"index": 0,
"guid": "1dbb6a4e-f82d-4e32-bb4c-15ed783c70ca",
"isActive": true,
"balance": "$1,510.89",
"picture": "http://placehold.it/32x32",
"eyeColor": "green",
"registered": "2014-08-17T09:21:18 -10:00",
"tags": [
"consequat",
"ut",
"qui",
"nulla",
"do",
"sunt",
"anim"
]
};
const removeItems = ['balance', 'picture', 'tags']
console.log(formatObj(o, removeItems))
function formatObj(obj, removeItems) {
return {
...Object.keys(obj)
.filter(item => !isInArray(item, removeItems))
.reduce((newObj, item) => {
return {
...newObj, [item]: obj[item]
}
}, {})
}
}
function isInArray(value, array) {
return array.indexOf(value) > -1;
}
My issue with the accepted answer, from an ESLint rule standard, if you try to destructure:
const { notNeeded, alsoNotNeeded, ...rest } = { ...ogObject };
the 2 new variables, notNeeded and alsoNotNeeded may throw a warning or error depending on your setup since they are now unused. So why create new vars if unused?
I think you need to use the delete function truly.
export function deleteKeyFromObject(obj, key) {
return Object.fromEntries(Object.entries(obj).filter(el => el[0] !== key))
}
with lodash cloneDeep and delete
(note: lodash clone can be used instead for shallow objects)
const obj = {a: 1, b: 2, c: 3}
const unwantedKey = 'a'
const _ = require('lodash')
const objCopy = _.cloneDeep(obj)
delete objCopy[unwantedKey]
// objCopy = {b: 2, c: 3}
For my code I wanted a short version for the return value of map() but the multiline/mutli operations solutions were "ugly". The key feature is the old void(0) which resolve to undefined.
let o2 = {...o, age: 31, lastname: void(0)};
The property stays in the object:
console.log(o2) // {firstname: "Jane", lastname: undefined, age: 31}
but the transmit framework kills it for me (b.c. stringify):
console.log(JSON.stringify(o2)) // {"firstname":"Jane","age":31}
I wrote big function about issue for me. The function clear all values of props (not itself, only value), arrays etc. as multidimensional.
NOTE: The function clear elements in arrays and arrays become an empty array. Maybe this case can be added to function as optional.
https://gist.github.com/semihkeskindev/d979b169e4ee157503a76b06573ae868
function clearAllValues(data, byTypeOf = false) {
let clearValuesTypeOf = {
boolean: false,
number: 0,
string: '',
}
// clears array if data is array
if (Array.isArray(data)) {
data = [];
} else if (typeof data === 'object' && data !== null) {
// loops object if data is object
Object.keys(data).forEach((key, index) => {
// clears array if property value is array
if (Array.isArray(data[key])) {
data[key] = [];
} else if (typeof data[key] === 'object' && data !== null) {
data[key] = this.clearAllValues(data[key], byTypeOf);
} else {
// clears value by typeof value if second parameter is true
if (byTypeOf) {
data[key] = clearValuesTypeOf[typeof data[key]];
} else {
// value changes as null if second parameter is false
data[key] = null;
}
}
});
} else {
if (byTypeOf) {
data = clearValuesTypeOf[typeof data];
} else {
data = null;
}
}
return data;
}
Here is an example that clear all values without delete props
let object = {
name: 'Semih',
lastname: 'Keskin',
brothers: [
{
name: 'Melih Kayra',
age: 9,
}
],
sisters: [],
hobbies: {
cycling: true,
listeningMusic: true,
running: false,
}
}
console.log(object);
// output before changed: {"name":"Semih","lastname":"Keskin","brothers":[{"name":"Melih Kayra","age":9}],"sisters":[],"hobbies":{"cycling":true,"listeningMusic":true,"running":false}}
let clearObject = clearAllValues(object);
console.log(clearObject);
// output after changed: {"name":null,"lastname":null,"brothers":[],"sisters":[],"hobbies":{"cycling":null,"listeningMusic":null,"running":null}}
let clearObject2 = clearAllValues(object);
console.log(clearObject2);
// output after changed by typeof: {"name":"","lastname":"","brothers":[],"sisters":[],"hobbies":{"cycling":false,"listeningMusic":false,"running":false}}

Combine or merge JSON on node.js without jQuery

I have multiple JSON like those
var object1 = {name: "John"};
var object2 = {location: "San Jose"};
They are not nesting or anything like that. Just basically different fields. I need to combine them into one single JSON in node.js like this:
{name: "John", location: "San Jose"}
I can use jQuery just fine. Here is a working example in the browser:
http://jsfiddle.net/qhoc/agp54/
But if I do this in node.js, I don't want to load jQuery (which is a bit over use, plus node.js' jQuery doesn't work on my Windows machine).
So is there a simple way to do things similar to $.extend() without jQuery?
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).
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;
};
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);
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.
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
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.
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"}
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 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.
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' }
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"
// }
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}
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 }] }
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;
}
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;
}
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' }
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"}]

Categories