JS how to deep copy two objects [duplicate] - javascript

This question already has answers here:
What is the most efficient way to deep clone an object in JavaScript?
(67 answers)
Closed 1 year ago.
I have an obj1:
const obj1 = { val: {v: 0}}
I'm trying to deep copy it by doing:
const obj2 = {...obj1}
However the {v: 0} is still not copied, how would I do this>

I guess this is the easiest way, but a bit clumsy
const obj2 = JSON.parse(JSON.stringify(obj1))
Otherwise you need to write a recursive cloning function or use some library - just search for cloneDeep, copyDeep or smth along these lines.

You can use lodash-es package for this. It provides the function cloneDeep() that will recursively clone values.
Here is the package: https://www.npmjs.com/package/lodash-es
Here are the Docs: https://lodash.com/docs/4.17.15#cloneDeep
import { cloneDeep as _cloneDeep } from 'lodash-es';
const obj2 = _cloneDeep(obj1);

You are doing it how you should (with the spread operator). The spread operator will copy everything just fine.
const obj1 = { val: {v: 0} };
const obj2 = { ...obj1 };
console.log(obj2);
const obj1 = {
test: 1,
test2: {
t: 1,
f: () => console.log('hello')
}
};
const obj2 = { ...obj1 };
console.log( obj2 );
console.log( obj2.test2.f() );
If you were to (at any time) do a JSON.stringify on the object, you will lost any methods/functions or other things that don't translate to the json scheme so it's best to avoid doing that. Object destructuring is what you want.

I don't have enough rep to even flag but this is a cleeeeeear duplicate of a lot of questions
even googling the title would have been easier for you
anyway I use a module called rfdc that does just that, and lodash has a function to do it to
otherwise you can loop through your src object with a recursive function that adds fields to your dest object

Related

How to achieve shallow copy of destructured object in JS

Im trying to figure out what is the best way to achieve a reconstructed "destructured" shallow copy of an object. I mean, how can I get a referenced object with only a subset of keys, but who are connected to the original object? From let original={ a=1, b=2, c=3} to a reference connected let reconstructed= { a=1, c=3}... values of keys are strings or numbers. I tried workarounds but cannot get a comfortable solution for this. Help would be appreciated.
You could use an array containing the props you want, and then hacky nonsense with getters and setters to build an object that actually reads from/writes to a different object.
Note: I've never needed to do this. I think you might have better luck with a different general approach, like "Use the same object, but only display the properties that are appropriate instead of all of them".
let original={ a:1, b:2, c:3};
let propsInNewObject = ["a", "c"];
const reconstructed = propsInNewObject.reduce((obj, el) => {
Object.defineProperty(obj, el, {
get: () => original[el],
set: (value) => { original[el] = value },
enumerable: true
});
return obj;
}, {});
console.log(reconstructed, original);
reconstructed.a = 100;
console.log(reconstructed, original);
This might be the wrong answer because your question is unclear, especially regards which bit is the 'shallow' copy.
Your reconstructed object is a new, independent object, and not connected to the source object in any way.
let reconstructed = { a, b }
// ^ ^
// denotes a new object
The question is, what types might a and b, be? If the properties deconstructed from the source object are themselves references (other objects), then modifying the deconstructed value, either in its independent state, or when assigned to the reconstructed object, will change the source value too.
let foo = { a: 1, b: 2 }
let { a, b } = foo
a = 999
console.log(foo, a, b)
let bar = { baz: { msg: 'Hello World' } }
let { baz } = bar
let bar1 = { baz }
baz.msg = 'Hello Sailor'
console.log(bar, baz, bar1)

Clone object which have function stored inside

After cloning object with JSON.parse(JSON.stringify(object)) function which was stored inside first object is not cloned to second one:
obj1: {
first: true,
second: function() { return 'test';}
}
var obj2 = JSON.parse(JSON.stringify(obj1));
After cloning obj2 has only first property in itself and looks like this:
obj2: {
first: true
}
Is there a way to clone function property also?
Including a function in an object turns it into a JavaScript object rather than a JSON object, as JSON does not allow the use of functions as property values.
You try this
obj2 = { ...obj1 };
you can also use a library like lodash to deep clone your object and use it as
const _ = required('lodash');
obj2 = _.cloneDeep(obj1);
Functions cannot be encoded into JSON.
You can use the spread syntax for a shallow clone:
let obj1 = {a: 10, b: () => "test"};
let obj2 = {...obj1};
// obj2: {a: 10, b: () => "test"}
Note that this is a shallow clone. So suppose you have some other property c in obj1 that is an object, this code will not clone c. Rather it will just point obj2.c to the the same object as obj1.c.

JavaScript: Reverse object destructuring / refactoring code to update object [duplicate]

This question already has answers here:
Is it possible to destructure onto an existing object? (Javascript ES6)
(16 answers)
Closed 4 years ago.
TLDR: How to use destructuring to speed up updating parts of one object based on another object of the same interface?
I would like to use the new ECMA2015 - 2017 JavaScript to refactor my code.
For simplicity let's say I have an object, looking like this:
export interface myObj {
name: string;
id: number;
description: string;
someBool: boolean;
anotherBool: boolean;
}
(Export interface works, because I'm working in Angular using Typescript).
Here is the old es5 function:
updateMyObj = function(oldObj, newObj) {
var someBoolSaved = oldObj.someBool;
var anotherBoolSaved = oldObj.anotherBool;
oldObj = newObj;
oldObj.someBool = someBoolSaved;
oldObj.anotherBool = anotherBoolSaved;
}
As you can see the function should update some parts of the oldObj, but also keep some parts.
Here is my attempt at refactoring the code:
updateObj(oldObj, newObj) {
let {someBool, anotherBool} = oldObj;
oldObj = newObj;
// Here is the part where I don't know how to proceed.
}
But I don't know, how I can now assign the oldObj's bools to the saved bools.
An inelegant way would be
oldObj.someBool = someBool;
oldObj.anotherBool = anotherBool;
which in this example would be fine. But in my actual task, this costs many lines of code which is why I want to refactor.
I just can't figure out the right syntax.
My attempts at coding this look similar like this:
oldObj = {someBool, anotherBool}
but this doesn't work.
If you want to assign the destructured value to a property, you do that by specifying the property on the right-hand side of a : in the destructuring.
For instance: The following assigns newObj.a and newObj.c to oldObj.a and oldObj.c:
({a: oldObj.a, c: oldObj.c} = newObj);
// ^^^^^^^^-----^^^^^^^^---- destinations for a and c
(The () are necessary because otherwise the { at the beginning looks like the beginning of a block. If we were already in an expression context, you wouldn't need them.)
const oldObj = {a: "old a", b: "old b"};
const newObj = {a: "new a", c: "new c"};
({a: oldObj.a, c: oldObj.c} = newObj);
console.log(oldObj);
As Bergi points out in a comment on the question, it doesn't really buy you much over
oldObj.a = newObj.a;
oldObj.c = newObj.c;
That's one reason various pick notations have kicked around (that one's seen activity quite recently). If that proposal were accepted (and it doesn't even have a champion yet, so don't hold your breath), you'd have oldObj.{a, c} = newObj;.
const newObj = { ...oldObject, someBool: true, anotherBool: false};
Edit:
Is updating the old object really what you want to do?
In your original code you mutate oldObj as a side-effect of the function. This is generally regarded as bad practise. The following is an example of a pure function with no side effects.
const firstObj = { name: 'hi', someBool: true, anotherBool: true };
const secondObj = { name: 'bye', someBool: false };
const thirdObj = mergeObjects(firstObj, secondObj);
// work with thirdObj from now on
function mergeObjects(firstObj, secondObj): myObj {
return {
...secondObj,
firstObj.someBool,
firstObj.anotherBool
}
}

Ramda Js: Setting property on an object using a value from the same object

Using Ramda Js, I need to create a function that can set one object property using the value of a different property on the same object. My attempt so far is as follows:
var foo = R.set(R.lensProp('bar'), 'foo' + R.prop('foo'));
var result = foo({foo:"bar"});
Desired result:
{foo:"bar", bar:"foobar"}
Actual result:
{foo:"bar", bar: "foofunction f1(a) {... etc"}
Clearly I'm misunderstanding something here, and any insights into how to approach this would be appreciated.
Lenses are not a good fit when the value of one property depends on the value of another property. A lambda is probably best here:
const foo = o => R.assoc('bar', 'foo' + o.foo, o);
foo({foo: 'bar'});
// => {foo: 'bar', bar: 'foobar'}
I had just coded something like the answer from #davidchambers and then made a points-free version, only to show how much simpler the lambda actually is. Rather than throw it out, here's how bad it looks in comparison:
var foo = (obj) => R.assoc('bar', 'foo' + obj.foo, obj);
var foo = R.converge(R.assoc('bar'), [R.pipe(R.prop('foo'), R.concat('foo')), R.identity]);
These two, with an intermediate version are available on the Ramda REPL
I would slice the issue into 2 parts: first you need to copy the foo property of an object to bar, then change bar's value. There is no out of the box solution in ramda for the 1st, but you can use evolve for the second:
import { curry, assoc, compose, evolve } from 'ramda'
// String -> String -> {k: v}
const copyPropAs = curry((from, to, obj) => assoc(to, obj[from], obj))
// String -> String -> String
const prefix = curry((value, string) => value + string)
const fn = compose(
evolve({
foo: prefix('foo')
}),
copyPropAs('foo', 'bar')
)
fn({foo: 'bar'})
I know, that it's not all point free, but with this way the problematic part is isolated to a point where it can no longer be broken to smaller parts, and we can always come back to those to find better implementations.

Coffeescript one liner for creating hashmap with variable key

Is it possible to do the following in one line in coffeescript?
obj = {}
obj[key] = value
I tried:
obj = { "#{key}": value }
but it does not work.
It was removed from the language
Sorry for being tardy -- if I remember correctly, it was because some
of our other language features depend on having the key known at
compile time. For example, method overrides and super calls in
executable class bodies. We want to know the name of the key so that a
proper super call can be constructed.
Also, it makes it so that you have to closure-wrap objects when used
as expressions (the common case) whenever you have a dynamic key.
Finally, there's already a good syntax for dynamic keys in JavaScript
which is explicit about what you're doing: obj[key] = value.
There's something nice about having the {key: value, key: value} form
be restricted to "pure" identifiers as keys.
(obj = {})[key] = value
will compile to
var obj;
(obj = {})[key] = value;
This is normal javascript. The only benefit you get from coffeescript is that you don't have to pre-declare var s because it does it for you.
For anyone that finds this question in the future, as of CoffeeScript 1.9.1 interpolated object literal keys are once again supported!
The syntax looks like this:
myObject =
a: 1
"#{ 1 + 2 }": 3
See https://github.com/jashkenas/coffeescript/commit/76c076db555c9ac7c325c3b285cd74644a9bf0d2
Depending on how complex your key is you can always use a variable name matching your key and use it to define an object, like this:
myKey = "Some Value"
obj = {myKey}
Which will compile to:
var myKey, obj;
myKey = "Some Value";
obj = {
myKey: myKey
};
So what you end up with is something close to what you seek, but that requires your keys to be valid variable names.
If you're using underscore, you can use the _.object function, which is the inverse of the _.pairs function.
_.pairs({a: 1, b: 'hello'})
//=> [['a', 1], ['b', 'hello']]
_.object([['a', 1], ['b', 'hello']])
//=> {a: 1, b: 'hello'}
So, assuming myKey = 'superkey' and myValue = 100 you could use:
var obj = _.object([[myKey, myValue]]);
//=> obj = {superkey: 100}

Categories