jquery $.extend recursive deep copy - javascript

How to know what the first param in $.extend does? It says deep copy but what does it means?
I try it but it doesn't shows any different in the result
http://jsfiddle.net/rvbrw0p9/
$(document).ready(function() {
var object1 = { a: 1, b: 2, c: 3 };
var object2 = { a: 'a', b: 2, c: 'c'};
var r = $.extend(object1 , object2 );
var r2 = $.extend(true, object1 , object2 );
console.log(r);
console.log(r2);
});

Technically there is no different from r and r2.
But please take note on the $.extend() behaviour http://api.jquery.com/jQuery.extend/
NOTE 1 jQuery.extend( target [, object1 ] [, objectN ] )
var r = $.extend(object1 , object2 );
// mean now we merge object2 into object1 so object1={ a: 'a', b: 2, c: 'c'}
console.log(object1) // return { a: 'a', b: 2, c: 'c'}
console.log(r) // return { a: 'a', b: 2, c: 'c'}
NOTE 2 jQuery.extend( [deep ], target, object1 [, objectN ] )
var objA = { k: 1, b: 2};
var objB = { k: 2, b: 'b', z:9};
var ret = $.extend(true, objA, objB); // when true as first parameter = merge recursive (deep copy)
console.log(objA); // return { k: 2, b: 'b', z:9}
console.log(ret); // return { k: 2, b: 'b', z:9}
NOTE 3 What happen if we pass False or {} as first param.
var objA = { k: 1, b: 2};
var objB = { k: 2, b: 'b', z:9};
var ret = $.extend(false, objA, objB);
console.log(objA) // return { k: 1, b: 2}
console.log(ret) // return { k: 2, b: 'b', z:9}
From the above example we can see True deep copy will update target value accordingly by other objectN value

Related

I want to create an object with the key as a property from the object and value as an array of objects matching the key (javascript)

I have a given object to iterate and create another object in the below format (newObj)
Given object:
let obj = [
{a: 1, b: 232},
{a: 1, b: 2},
{a: 1, b: 256},
{a: 2, b: 3},
{a: 2, b: 3343},
{a: 3, b: 4}
];
Expected object:
newObj = {
1: [{a: 1, b: 232}, {a: 1, b: 2}, {a: 1, b: 256}],
2: [{a: 2, b: 3}],
3: [{a: 3, b: 4}]
}
Code:
let newObj = {};
obj.forEach(element => {
if (newObj[element.a]) {
let key = element.a;
newObj[key] = newObj[key].push(element);
}
newObj[element.a] = [element];
});
console.log(newObj);
We create a result object, loop through every object in obj array, if we don't have the object a key in the result object, we add him (a: []), and after that we push the entire object to result[a] array
let obj = [
{a: 1, b: 232},
{a: 1, b: 2},
{a: 1, b: 256},
{a: 2, b: 3},
{a: 2, b: 3343},
{a: 3, b: 4}
];
let result = {};
for(const {a, b} of obj) {
if(!result[a]) result[a] = []
result[a].push({a, b})
}
console.log(result)
To address your updated code snippet, you need to only create a new array for a given key if they key does not exist.
let obj = [
{ a: 1, b: 232 },
{ a: 1, b: 2 },
{ a: 1, b: 256 },
{ a: 2, b: 3 },
{ a: 2, b: 3343 },
{ a: 3, b: 4 }
];
let newObj = {};
obj.forEach(element => {
let key = element.a;
if (!newObj[key]) {
newObj[key] = []; // Only initialize if undefined/null
}
newObj[key].push(element); // Always push
});
console.log(newObj);
.as-console-wrapper { top: 0; max-height: 100% !important; }
A more modern approach would be to simply bin them by the a key by reducing and spreading.
const obj = [
{ a: 1, b: 232 },
{ a: 1, b: 2 },
{ a: 1, b: 256 },
{ a: 2, b: 3 },
{ a: 2, b: 3343 },
{ a: 3, b: 4 }
];
const newObj = obj.reduce((acc, o) => ({
...acc,
[o.a]: [...(acc[o.a] ?? []), o]
}), {});
console.log(newObj);
.as-console-wrapper { top: 0; max-height: 100% !important; }
you can use reduce for that
let obj = [
{a: 1, b: 232},
{a: 1, b: 2},
{a: 1, b: 256},
{a: 2, b: 3},
{a: 2, b: 3343},
{a: 3, b: 4}
];
const newObj = obj.reduce((res, {a, b}) => {
return {
...res,
[a] : [...(res[a] || []), {a, b}]
}
}, {})
console.log(newObj)

How would you check if property name(s) from one object exist in another?

I am trying to transfer/copy properties from object1 to object2, but only properties that are undefined in object2.
Thanks in advance, I hope this comes across clearly!
let object1 = { a: 1, b: 2, c: 3, d: 4 }
let object2 = { a: 'string' }
fillObj = function (object2, object1) {
for (let key in object1) {
if (typeof object2.key === undefined) {
object2[key] = object1[key];
}
}
return object2; //should return {a: 'string', b: 2, c: 3, d: 4 }
};
(1) Look properties on an object by a variable property name by using bracket notation, not dot notation
(2) To check if something is undefined, either compare against undefined directly, or use typeof and compare against the string 'undefined' (but this check isn't needed for this algorithm)
(3) Make sure the properties are own properties, not inherited properties, with hasOwnProperty
let object1 = { a: 'string' }
let object2 = { a: 1, b: 2, c: 3, d: 4 }
fillObj = function (object2, object1) {
for (let key in object1) {
if (object1.hasOwnProperty(key)) {
object2[key] = object1[key];
}
}
return object2; //should return {a: 'string', b: 2, c: 3, d: 4 }
};
console.log(fillObj(object2, object1));
Or use Object.entries, which iterates over own-properties only:
let object1 = { a: 'string' }
let object2 = { a: 1, b: 2, c: 3, d: 4 }
fillObj = function (object2, object1) {
for (const [key, val] of Object.entries(object1)) {
object2[key] = val;
}
return object2; //should return {a: 'string', b: 2, c: 3, d: 4 }
};
console.log(fillObj(object2, object1));

If object has specific properties create a new object only with them

As always I will explain my problem by example (that I solved but its a lot of code and its ugly, that's why I'm looking for a better solution). I'm trying to look at an object like this:
const object1 = {
a: {a:1},
b: 2,
c: 3,
d: 4,
};
I want to check if this object has any of the following properties [a,f] and if have one of them to create a new object with these properties
const object2 = {
a: {a:1},
};
const object1 = {
a: {a:1},
b: 2,
c: 3,
d: 4,
}
const arrOfItem = ['a', 'd']
const newObj = {}
for(let item in object1) {
if(arrOfItem.includes(item)) {
newObj[item]= object1[item]
}
}
console.log(newObj)
see if this works for you,
function makeObject (properties) {
const originalObject = {
a: {a:1},
b: 2,
c: 3,
d: 4,
};
let newObject = {}
properties.forEach(property => {
if(originalObject.hasOwnProperty(property)) {
newObject[property] = originalObject[property];
}
});
return newObject;
}
pass the properties as an array of strings to makeObject function
const d = ['a', 'f', 'd']
const object1 = {
a: {a:1},
b: 2,
c: 3,
d: 4,
};
const object2 = d.reduce((acc, ele) => {
if(object1[ele] !== undefined) acc[ele] = object1[ele];
return acc;
}, {});
console.log(object2);

Reduce and object deconstruction/assignment

Let's assume I have two simple objects and I want to create a third one that will be joining their properties. This works perfectly:
(()=>{
const a1 = {a: 2, b: 3}
const b1 = {a: 100, c: 5}
return {...a1, ...b1}
})()
// { a: 100, b: 3, c: 5 }
But it stops working once I try to create a new object derived from b1 using .reduce. For a sake of simplicity let's create a reduce function that simply makes a shallow copy of the b1 object:
let r = (()=>{
const a1 = {a: 2, b: 3}
const b1 = {a: 100, c: 5},
b2 = Object.entries(b1).reduce((acc, [key, value])=>Object.defineProperty(acc, key, {value}), {})
console.log(b2) // {a: 100 c: 5}
return {...a1, ...b2}
})()
console.log(r);// { a: 2, b: 3 }
I have a feeling that there is something about .reduce function that I just don't understand. What can I do to fix this?
By default, properties created with defineProperty are not enumerable, so they won't be included with a spread.
To fix:
b2 = Object.entries(b1).reduce((acc, [key, value]) =>
Object.defineProperty(acc, key, {value, enumerable: true})
, {})
You should mark the property as enumerable
Object.defineProperty(acc, key, {value, enumerable: true});
Why not just using the function Object.assign instead, it's straightforward.
let r = (()=> {
const a1 = {a: 2, b: 3};
const b1 = {a: 100, c: 5};
const b2 = Object.entries(b1).reduce((acc, [key, value]) => Object.assign(acc, {[key]: value}), {})
console.log(b2); // {a: 100 c: 5}
return {...a1, ...b2}
})()
console.log(r); // { a: 2, b: 3 }
One fix could be to use Object.assign to create a copy of b1 like:
let r = (()=>{
const a1 = {a: 2, b: 3}
const b1 = {a: 100, c: 5}
const b2 = Object.assign({}, b1)
console.log(b2) // {a: 100 c: 5}
return {...a1, ...b2}
})()
console.log(r); // { a: 100, b: 3, c: 5 }

How to copy/overwrite an object using Object.assign() function?

How to fully copy / overwrite an object using Object.assign()?
If there would be another approach, it would be highly appreciated. :)
The purpose is to update the existing object to its new value.
Below is my code snippet and the expected result should be the same as the value of object2 only.
Expected result: { a: 8, b: 7 }
const object1 = {
a: 1,
b: 2,
c: {
d: 3
}
};
const object2 = {
a: 8,
b: 7
};
Object.assign(object1, object2);
console.log(object1);
For keeping the same object reference, you could remove all properties in advance and then assign the wanted properties with Object.assign.
const object1 = { a: 1, b: 2, c: { d: 3 } };
const object2 = { a: 8, b: 7 };
Object.assign(
Object.keys(object1).reduce((o, k) => (Reflect.deleteProperty(o, k), o), object1),
object2
);
console.log(object1);
IE
var object1 = { a: 1, b: 2, c: { d: 3 } },
object2 = { a: 8, b: 7 };
Object.keys(object2).reduce(
function (object, key) {
object[key] = object2[key];
return object;
},
Object.keys(object1).reduce(function (object, key) {
delete object[key];
return object;
}, object1)
);
console.log(object1);
If you want to override the object1 properties with those from object2, you need to do it like this:
object1 = Object.assign({}, object2);
But with this you need to declare object1 with var keyword so you can assign a new value to it.
Demo:
var object1 = {
a: 1,
b: 2,
c: {
d: 3
}
};
const object2 = {
a: 8,
b: 7
};
object1 = Object.assign({}, object2);
console.log(object1);

Categories