Languages
[Edit]
EN

JavaScript - how to clone object?

4 points
Created by:
Kate_C
2845

In JavaScript there are available few ways to clone object. In this article simple solutions how to do it has been presented.

1. Object.assign method example

This approach makes copy of first level entries.

// ONLINE-RUNNER:browser;

function cloneObject(object) {
	return Object.assign(new Object(), object);
}


// Example:

var studentObject = {
    name: 'John',
    age: 25,
    todos: [
        'Sleeping', 'Lectures', 'Classes', 'Shopping'
    ],
    action: function() { /* ... */ }
}

var studentObjectCopy = cloneObject(studentObject);

studentObject.age = 30;
studentObject.todos[0] = 'Modiffied Sleeping';

console.log(studentObject.name + ' ' + studentObject.age);
console.log(studentObject.todos);
console.log(studentObject.action);

console.log(studentObjectCopy.name + ' ' + studentObjectCopy.age);
console.log(studentObjectCopy.todos);
console.log(studentObjectCopy.action);

Note: this approach has ben introducd in ECMAScript 2015.

2. Spread syntax example

This approach makes copy of first level entries.

// ONLINE-RUNNER:browser;

var studentObject = {
    name: 'John',
    age: 25,
    todos: [
        'Sleeping', 'Lectures', 'Classes', 'Shopping'
    ],
    action: function() { /* ... */ }
}

var studentObjectCopy = { ...studentObject };

studentObject.age = 30;
studentObject.todos[0] = 'Modiffied Sleeping';

console.log(studentObject.name + ' ' + studentObject.age);
console.log(studentObject.todos);
console.log(studentObject.action);

console.log(studentObjectCopy.name + ' ' + studentObjectCopy.age);
console.log(studentObjectCopy.todos);
console.log(studentObjectCopy.action);

Note: this approach has been intorduced in ECMAScript 2018.

3. Custom clone function example

Note: read this article to know how to check types in JavaScript. 

// ONLINE-RUNNER:browser;

function getType(object) {
	return Object.prototype.toString.call(object);
}

function cloneArray(array) {
	let result = [ ];
	for (var i = 0; i < array.length; ++i) {
		result.push(cloneEntry(array[i]));
	}
	return result;	
}

function cloneObject(object) {
	let result = new Object();
	for (var property in object) {
		if (object.hasOwnProperty(property)) {
			result[property] = cloneEntry(object[property]);
		}
	}
	return result;	
}

function cloneEntry(entry) {
  	var type = getType(entry);
  
  	switch(type) {
        case '[object Array]':     return cloneArray(entry);
        case '[object Object]':    return cloneObject(entry);
        case '[object Null]':      return null;
        case '[object Undefined]': return undefined;
        case '[object Boolean]':   return Boolean(entry);
        case '[object Number]':    return Number(entry);
        case '[object BigInt]':    return BigInt(entry);
        case '[object String]':    return String(entry);
        case '[object Date]':      return new Date(entry.getTime());
        case '[object Function]':  throw new Error('Function type is not allowed.');
        default:                   throw new Error(type + ' copy operation is not supported.');
	}
}


// Example:

var studentObject = {
    name: 'John',
    age: 25,
    todos: [
        'Sleeping', 'Lectures', 'Classes', 'Shopping'
    ]
}

var studentObjectCopy = cloneEntry(studentObject);

console.log(studentObject.name + ' ' + studentObject.age 
            + ' ' + studentObject.todos);

console.log(studentObjectCopy.name + ' ' + studentObjectCopy.age 
            + ' ' + studentObjectCopy.todos);

4. Converting to JSON and back example

This approach makes deep cloning avoiding functions and added entries (properties or methods) to objects e.g. additional properties inside Array type object - some entries are still not coppied.

// ONLINE-RUNNER:browser;

function cloneObject(object) {
  	var json = JSON.stringify(object);
  
	return JSON.parse(json);
}


// Example:

var studentObject = {
    name: 'John',
    age: 25,
    todos: [
        'Sleeping', 'Lectures', 'Classes', 'Shopping'
    ],
    action: function() { /* ... */ }
}


var studentObjectCopy = cloneObject(studentObject);

studentObject.todos.property = 'This is property value';

console.log(studentObject.name + ' ' + studentObject.age);
console.log(studentObject.todos);

console.log(studentObjectCopy.name + ' ' + studentObjectCopy.age);
console.log(studentObjectCopy.todos);

console.log(studentObject.action + '  vs  ' + studentObjectCopy.action);
console.log(studentObject.todos.property + '  vs  ' + studentObjectCopy.todos.property);

5. Custom clone function vs clone with converting to JSON performance

// ONLINE-RUNNER:browser;

var count = 100000;

var studentObject = {
    name: 'John',
    age: 25,
    todos: [
        'Sleeping', 'Lectures', 'Classes', 'Shopping'
    ]
}

// Test 1: clone with converting to json

;(function() {
    function cloneObject(object) {
        var json = JSON.stringify(object);

        return JSON.parse(json);
    }
  
    var t1 = new Date();

    for(var i = 0; i < count; ++i) {
        var studentObjectCopy = cloneObject(studentObject);
    }

    var t2 = new Date();
    var dt = t2 - t1;

    console.log(dt + 'ms <- clone with converting to json');
})();

// Test 2: custom deep clone

;(function() {
    function getType(object) {
        return Object.prototype.toString.call(object);
    }

    function cloneArray(array) {
        let result = [ ];
        for (var i = 0; i < array.length; ++i) {
            result.push(cloneEntry(array[i]));
        }
        return result;	
    }

    function cloneObject(object) {
        let result = new Object();
        for (var property in object) {
            if (object.hasOwnProperty(property)) {
                result[property] = cloneEntry(object[property]);
            }
        }
        return result;	
    }

    function cloneEntry(entry) {
        var type = getType(entry);

        switch(type) {
            case '[object Array]':     return cloneArray(entry);
            case '[object Object]':    return cloneObject(entry);
            case '[object Null]':      return null;
            case '[object Undefined]': return undefined;
            case '[object Boolean]':   return Boolean(entry);
            case '[object Number]':    return Number(entry);
            case '[object BigInt]':    return BigInt(entry);
            case '[object String]':    return String(entry);
            case '[object Date]':      return Date(entry);
            case '[object Function]':  throw new Error('Function type is not allowed.');
            default:                   throw new Error(type + ' copy operation is not supported.');
        }
    }

	var t1 = new Date();

    for(var i = 0; i < count; ++i) {
        var studentObjectCopy = cloneEntry(studentObject);
    }

    var t2 = new Date();
    var dt = t2 - t1;

    console.log(dt + 'ms <- custom deep clone');
})();

 

Checkout latest findings & news:

Checkout latest questions:

Checkout latest wiki articles:

Hey ūüĎč
Would you like to know what we do?
  • Dirask is a friendly IT community for learners, professionals and hobbyists to share their knowledge and help each other in extraordinary easy way.
  • We welcome everyone,
    no matter what the experience,
    no matter how basic the question is,
    this community will help you.
Rockstar community members
Thank you for great work ūüĎć