How to copy json object without reference in vue?

Viewed 13054

In my component i have declarated some data like this:

data() {
    return {
        defaultValue: {json object with some structure},
        activeValue: {}
        ...

And in component methods a make copy this value:

this.activeValue = this.defaultValue

But problem is, after change this.activeValue value a have changes in this.defaultValue too.

If i use Object.freeze(this.defaultValue) and trying change this.activeValue i have get error - object is not writable.

How i can make copy of data but without reference?

7 Answers

If you have simple object, quickest and easiest way is to just use JSON.parse and JSON.stringify;

const obj = {};

const objNoReference = JSON.parse(JSON.stringify(obj));
this.activeValue = { ...this.defaultValue }

Using an ES6 spread operator will help you to do a copy if you do not have a nested object. If you equate using equal = sign, it will not create a new object, it will just create a variable with the reference to the current object (like a shallow copy).

To do a complete deep copy, even it is nested object, go for this:

 const objNoReference = JSON.parse(JSON.stringify(obj));

as suggested by Owl.

Click to read more for better understanding of the concept

Objects are assigned and copied by reference.

All operations via copied references (like adding/removing properties) are performed on the same single object.

To make a “real copy” (a clone) we can use Object.assign for the so-called “shallow copy” (nested objects are copied by reference).

For “deep cloning” use _.cloneDeep(obj) from loadash library.

JSON stringify&parse method have some issues like converting date objects to strings. It also cannot handle special data types like Map,Set,function etc... This is prone to future bugs.

I use the following method to deep copy an object.

REMEMBER! this is not a complete application of cloning. There are more data types to handle like Blob, RegExp etc...

  const deepClone = (inObject) => {
            let outObject, value, key

            if (typeof inObject !== "object" || inObject === null) 
                return inObject
            
            if (inObject instanceof Map) {
                outObject = new Map(inObject);
                for ([key, value] of outObject)
                    outObject.set(key, deepClone(value))
            } else if (inObject instanceof Set) {
                outObject = new Set();
                for (value of inObject)
                    outObject.add(deepClone(value))
            } else if (inObject instanceof Date) {
                outObject = new Date(+inObject)
            } else {
                outObject = Array.isArray(inObject) ? [] : {}
                for (key in inObject) {
                    value = inObject[key]
                    outObject[key] = deepClone(value)
                }
            }
            return outObject
        }

You can use 'JSON.parse and stringify' or using some clone function in the libs like lodash (underscore, ramda...)

Also a simple solution is to store defaultValue: {json object with some structure} with JSON.stringify(defaultValue) in a string variable:

var x = JSON.stringify(this.defaultValue);

If you need it as JSON object again you can get it with JSON.parse():

var newObject = JSON.parse(x);

The object reference is also broken doing it this way, x will stay unchanged if the content of the object defaultValue is altered.

Related