How to combine objects with objects.assign? - javascript

My simple code
const ob1 = {
a: 'pokushevski',
b: '2001',
};
const obj2 = {
obj1: {},
c: '1999',
};
const result = Object.assign(ob1, obj2);
console.log(result);
console.log(Object.getOwnPropertyNames(result));
Output
{ a: 'pokushevski', b: '2001', obj1: {}, c: '1999' }
[ 'a', 'b', 'obj1', 'c' ]
It seems that obj1 in result appears just as any other attribute,without having any reference to const obj1.
Why?

What you are doing right now is basically merging ob1 (without 'j') with obj2 (with 'j'), and since obj1 (with 'j') is an empty object inside of obj2, it gets added as a property on the resulting merged object.
What else did you expect, and can we help in getting you there?
Maybe you actually made a typo and wanted the first object ob1 to be named obj1 instead, then to be used as a property within obj2 and finally merge the two objects?
If so you co do:
const obj1 = {
a: 'pokushevski',
b: '2001',
};
const obj2 = {
obj1, // shorthand syntax, property will be named the same as the const
c: '1999',
};
// avoid mutation by using a new object as the target
const result = Object.assign({}, obj1, obj2);
// Display result and property names
console.log(result);
console.log(Object.getOwnPropertyNames(result));
If you only wanted to add obj1 within obj2 you don't need Object.assign
Watch out for what's mutable
With the code above, the original obj1 gets modified whenever you update result.obj1 properties. Try to update result.obj1.a and then console.log(obj1)
If you want to prevent this, you can use destructuring like so:
const obj1 = {
a: 'pokushevski',
b: '2001',
};
// Create a shallow copy of `obj1` to prevent mutating the original
// object by updating `obj2.obj1` properties
const obj2 = {
obj1: {...obj1},
c: '1999',
};
// Avoid mutating the original `obj1` by using a new object as the target
const result = Object.assign({}, obj1, obj2);
// Display result and property names
console.log(result);
console.log(Object.getOwnPropertyNames(result))
If you really want to keep using Object.assign instead of destructuring you can replace obj1: {...obj1} by obj1: Object.assign({}, obj1)

I guess that you want ob1 to be obj1 inside obj2
Then this is a way to do it:
const ob1 = {
a: 'pokushevski',
b: '2001',
};
const obj2 = {
obj1: {},
c: '1999',
};
const result = Object.assign({}, obj2);
Object.assign(result.obj1, ob1);
console.log(result);
console.log(Object.getOwnPropertyNames(result));

Related

Javascript (ES6 + Lodash) merge source object with another updating only common properties, deeply

I have to deeply update an object with a provided one
, keeping only the properties/paths found in the source object.
I tried Lodash.merge, but it merges all the properties of the second object, I want to merge only the properties found in the source object.
Here is an example:
const ob1 = {
a1: {
b1: 2
},
a2: 5
}
const obj2 = {
a1: {
b1: 4,
b2: 9
},
a3: 6
}
expected result = {
a1: {
b1: 4
},
a2: 5
}
I'd like the simplest solution with es6 or lodash utils.
Any ideas? Thanks!
If you want a custom merge strategy, perhaps you can write your own recursive function. In the recursive function, you basically pass in your target and your source. Based on your question, the target will be obj1 and the source will be obj2.
Your logic is that:
If obj1 does not contain a key that is in obj2, we keep the key-value pair from the obj1, the source
If obj1 contains a key that is obj2, then:
If they are simply non-objects, we allow obj2 value to override obj1 value
If they are both objects, then we call the same recursive function again
See proof-of-concept below:
const obj1 = {
a1: {
b1: 2
},
a2: 5
}
const obj2 = {
a1: {
b1: 4,
b2: 9
},
a3: 6
}
function smartMerge(target, source) {
const o = {};
// Iterate throught all keys in your target
for(let k in target) {
// If a matching key is found in source
if (k in source) {
// If they are both objects, then we run recurisve merge logic
if (typeof target[k] === 'object' && typeof source[k] === 'object') {
o[k] = smartMerge(target[k], source[k]);
}
// Otherwise, we let the source override the value
else {
o[k] = source[k];
}
}
// If no matching key is found, we keep the target value
else {
o[k] = target[k];
}
}
return o;
}
const result = smartMerge(obj1, obj2);
/* Expected:
{
a1: {
b1: 4
},
a2: 5
}
*/
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

How to use a destructuring assignment inside an object

Is it possible to use a destructuring assignment inside an object?
This works
const test = {a: 'hey', b: 'hello'}
const {a,b} = test;
const destruct = {
a,
b
};
Would like to do this
const test = {a: 'hey', b: 'hello'}
// something like this
const destruct = {
{a,b}: test
};
const destruct = {
{a}: test,
{b}: test
};
If I understand correctly, it seems the spread syntax is a good fit for what you need.
The spread syntax "..." allows you to "spread" the key/value pairs from a source object (ie test) to a target object (ie destruct):
const test = {
a: 'hey',
b: 'hello',
c: 'goodbye'
}
const destruct = {
// {a,b}: test <-- invalid syntax
...test // equivalent using the "spread" syntax
};
console.log(destruct)
Additionally, if you wanted to select a subset of keys from a source object and spread those into a target object then this can be achieved by the following:
const test = {
a: 'hey',
b: 'hello',
c: 'goodbye'
}
/* Spread subset of keys from source object to target object */
const welcomeOnly = {
...({ a, b } = test, { a, b })
}
console.log('exclude goodbye, show welcomes only:', welcomeOnly);
The second example works by destructing the source object (ie test) into an object, with the subset of keys that we want (a and b).
In the scope of that expression (ie everything between the ( and )), these keys are accessible as local variables. We take advantage of this, and pass those to a new object (ie { a, b }). Because the new object is declared after the ,, it is returned as the result of the expression.
If you are trying to take a subset of properties you can use the rest operator
const test = {
a: 'hey',
b: 'hello',
c: 'goodbye'
};
const { c, ...destruct } = test;
console.log(destruct);
This assigns c to a const and the the left over properties are assigned to the const destruct. List all the unwanted properties first and then the left over properties are caught with the rest operator.
Works with arrays as well.
const test = ['hey', 'hello', 'goodbye'];
const [ first, ...rest ] = test;
console.log(rest);
You can try to work like this for destructuring arrays!
let abc = {
a: 'hello',
b: 'hey',
c: 'hi, there!'
}
let {a: x, b:y, c:z} = abc;
console.log(x,y,z)
// "hello"
"hey"
"hi, there!"

Merge objects in javascript while ignoring property values that are undefined (jQuery.fn.extend behavior)

I'm looking for an implementation of jQuery.fn.extend in typescript/javascript. Specifically, I'm interested in the part where it ignores undefined values in the source object.
const obj1 = {
a: 1,
b: undefined
};
const obj2 = {
a: undefined, // Should be ignored.
b: 100
};
const merged = $.extend(obj1, obj2);
console.log(merged); // {a: 1, b: 100}
The structure of the objects to be merged is not necessarily well-known and one may contain more properties than the other.
You could define a helper function that would create an object with the undefined properties removed:
const definedProps = obj => Object.fromEntries(
Object.entries(obj).filter(([k, v]) => v !== undefined)
);
And then the merge becomes:
const merged = Object.assign(obj1, definedProps(obj2));
const obj1 = {
a: 1,
b: undefined
};
const obj2 = {
a: undefined, // Should be ignored.
b: 100
};
const definedProps = obj => Object.fromEntries(
Object.entries(obj).filter(([k, v]) => v !== undefined)
);
const merged = Object.assign(obj1, definedProps(obj2));
console.log(merged);
This solution uses Object.fromEntries which is rather new, but it is easy to polyfill
Object.fromEntries = arr => Object.assign({}, ...arr.map( ([k, v]) => ({[k]: v}) ));

Cloning javascript object omitting one property [duplicate]

This question already has answers here:
Simplest way to copy JS object and filter out certain properties
(6 answers)
Remove key-value pair from JSON object
(7 answers)
Javascript - Removing object key not using delete
(2 answers)
Closed 3 years ago.
What's the best way in JavaScript for returning an object omitting just one or more properties?
I can assign a key to undefined and that works for sure, but what if want to completely get rid of that key?
function removeCKey() {
const obj = {a: 'a', b: 'b', c: 'c'}
return {
...obj,
c: undefined,
};
}
const myObj = removeCKey();
Also, I want to avoid creating an intermediate object where I use the spread operator like this
function removeCKey() {
const obj = {a: 'a', b: 'b', c: 'c'}
const {c, ...rest} = newObj
return rest;
}
const myObj = removeCKey();
You can use ES6 object destructuring assignment.
function removeKeys() {
const obj = {
a: 'a',
b: 'b',
c: 'c'
};
// extract property c in variable c
// and rest of the value into res
let { c, ...res } = obj;
return res;
}
console.log(removeKeys())
Just delete what you don't need:
function omit(obj, keys) {
const newObj = { ...obj }; // shallow copy...
keys.forEach(key => {
delete newObj[key]; // ... and `delete`.
});
return newObj;
}
omit({a: 'a', b: 'b', c: 'c'}, ['c']);
outputs
{ a: 'a', b: 'b' }

reconstruct partial deconstructed object es6

I am looking for the most concise way to have a new object out of the fields of the deconstructed one.
let obj = {
a: 1,
b: 2,
c: null
}
Currently I have:
let {a, c} = obj;
let data = {a, c}
What I wished I would be having:
let data = {a, c} = obj;
// but data actually becomes {a, b, c}
// and not {a, b} as I wished it to be.
Although your code looks fine may be if your task consists in cherrypicking keys and put it in another object destructuring is not the best approach:
const object = { a: 5, b: 6, c: 7 };
const picked = (({ a, c }) => ({ a, c }))(object);
console.log(picked)
You can define a function that will provide the destructured object as the return value, and assign the call to data:
const obj = {
a: 1,
b: 2,
c: null
}
const partial = ({ a, c }) => ({ a, c })
const data = partial(obj)
console.log(data)
Unfortunately this isn't possible in one line without some setup, but the setup is worthwhile if you are creating the same partial object a lot of places in your source.
Rather than rely on destructuring for this, you can implement a version of the commonly found "pick" function, that accepts as input an object and an array of keys to pull out of that object:
function pick(obj, keys) {
return keys.reduce((memo, key) => {
memo[key] = obj[key];
return memo;
}, {});
}
const obj = { a: 1, b: 2, c: 3 }
const data = pick(obj, ['a', 'b']);
console.log(data); // { a: 1, b: 2}
Normally I would consider performance less important than readability, which is highly subjective. But in this case, both the pick solution above and the one-liners are orders of magnitude slower than your original two-liner, though pick wins out over the one-liner by a comparatively small margin: https://jsperf.com/testaagwt14124oih1oij

Categories