EN
JavaScript - clone object
4
points
In this article, we would like to show you how to clone objects in JavaScript.
1. Object.assign
method example
This approach makes copies 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 copies 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 copied.
// 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');
})();