Can I Use Destructuring To Create A Deep Copy?
Solution 1:
You can't create new objects with destructuring, no. You can only pick out values that exist on the source, you can't perform transformations on them. (You can change the variable name you use, but you can't transform the value.) I've often wanted to, but you can't (at least, not at present).
There are various jump-through-the-hoops ways you could do it, but really the simplest is going to be to make a shallow copy of the array separately.
A simpler example:
const obj = {
foo: "bar",
array: [1, 2, 3]
};
const {foo} = obj;
const array = obj.array.slice(); // or: = [...obj.array];
obj.array[0] = "one";
console.log(obj.array[0]); // "one"
console.log(array[0]); // 1
Solution 2:
It is not possible directly.
let { object } = a;
object = {...object}; // Object.assign({}, object); <<
object.array = [0, ...object.array, 0];
console.log(object.array); // [0, 4, 5, 6, 0]
console.log(a.object.array); // [4, 5, 6]
Solution 3:
Answer
You can achieve this by using a Proxy
Object, either through a function, or directly.
Using a Function during Destruct:
The Proxy
object takes the target
object, and a handler
.
A handler
allows you to set certain conditions like get
and set
that can alter the way that data is returned to the user. We'll be using get
for this.
In the below handler, we alter the get
functionality. We check if the target[prop]
returns an Array
or Object
. If it does, we create a copy in memory and return that instead of the reference. If it is not an Array
or Object
we simply return the primitive value (string, number, etc)
let copyHandler = {
get: function( target, prop, receiver ) {
let value = target[ prop ];
if ( Array.isArray( value ) ) return value.slice( 0 );
if ( typeof value === "object" && value.constructor.name === "Object" ) return Object.assign( {}, value );
return value;
}
}, getCopy = obj => new Proxy(obj, copyHandler);
Utilizing the getCopy
function as our destructuring middle-man, we can be sure that all our values return new references:
const {
name,
testArray,
object
} = getCopy(a);
object.array = [...object.array, 0];
console.log(a.object.array); // [4,5,6]
console.log(object.array); // [4,5,6,0]
Example:
let copyHandler = {
get: function( target, prop, receiver ) {
let value = target[ prop ];
if ( Array.isArray( value ) ) return value.slice( 0 );
if ( typeof value === "object" && value.constructor.name === "Object" ) return Object.assign( {}, value );
return value;
}
}, getCopy = obj => new Proxy(obj, copyHandler);
let a = {
name: 'lala',
testArray: [ 1, 2, 3 ],
object: {
name: 'object',
array: [ 4, 5, 6 ]
}
};
const {
name,
testArray,
object
} = getCopy(a);
object.array = [...object.array, 0];
console.log(a.object.array); // [4,5,6]
console.log(object.array); // [4,5,6,0]
Alternatively, we can do it directly on Declaration/Initialization/Reception:
Directly in this sense means that we can setup the Object to return copies during destructured declaration only.
We do this similarly to above by utilizing a Proxy
, and a middle-man function.
Note: The middle-man functions aren't necessary, but it helps keep things organized.
let destructHandler = {
get: function( target, prop, receiver ) {
if(!this.received) this.received = new Set();
let value = target[ prop ];
if(this.received.has(prop)) return value;
this.received.add(prop);
if ( Array.isArray( value ) ) return value.slice( 0 );
if ( typeof value === "object" && value.constructor.name === "Object" ) return Object.assign( {}, value );
return value;
}, destructable = obj => new Proxy(obj, destructHandler);
The difference here is that our get
handler uses a Set
to determine whether or not a property has already been grabbed once.
It will return copies upon the first request for a referential property (an Array
or Object
). It will still return any primitive value as normal.
This means that upon declaring/initialization/reception of the object, you can apply the destructable
proxy and immediately afterwards pull out copies from that object using a destruct.
Initialization example code:
let a = destructable({
name: 'lala',
testArray: [ 1, 2, 3 ],
object: {
name: 'object',
array: [ 4, 5, 6 ]
}
});
Destructure example:
const {
name,
testArray,
object
} = a;
object.array = [...object.array, 0];
console.log(a.object.array); // [4,5,6]
console.log(object.array); // [4,5,6,0]
Example:
let destructHandler = {
get: function( target, prop, receiver ) {
if(!this.received) this.received = new Set();
let value = target[ prop ];
if(this.received.has(prop)) return value;
this.received.add(prop);
if ( Array.isArray( value ) ) return value.slice( 0 );
if ( typeof value === "object" && value.constructor.name === "Object" ) return Object.assign( {}, value );
return value;
}
}, destructable = obj => new Proxy(obj, destructHandler);
let a = destructable({
name: 'lala',
testArray: [ 1, 2, 3 ],
object: {
name: 'object',
array: [ 4, 5, 6 ]
}
});
const {
name,
testArray,
object
} = a;
object.array = [...object.array, 0];
console.log(object.array); // [4,5,6,0]
console.log(a.object.array); // [4,5,6]
Hope this helps! Happy Coding!
Post a Comment for "Can I Use Destructuring To Create A Deep Copy?"