103

If I clone an array, I use cloneArr = arr.slice()

I want to know how to clone an object in nodejs.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
guilin 桂林
  • 17,050
  • 29
  • 92
  • 146

15 Answers15

196

For utilities and classes where there is no need to squeeze every drop of performance, I often cheat and just use JSON to perform a deep copy:

function clone(a) {
   return JSON.parse(JSON.stringify(a));
}

This isn't the only answer or the most elegant answer; all of the other answers should be considered for production bottlenecks. However, this is a quick and dirty solution, quite effective, and useful in most situations where I would clone a simple hash of properties.

Kato
  • 40,352
  • 6
  • 119
  • 149
  • Good answer but note that "deep" is relative. It won't follow references to other objects. – djechlin Jun 27 '13 at 20:32
  • 2
    @djechlin Sure it does. Try it out: http://jsfiddle.net/katowulf/E5jC3/ (tested with node 0.10.11) It's not going to be able to reconstitute functions or prototypical data, but it gets the values around just fine. – Kato Jun 27 '13 at 20:42
  • 16
    This will convert dates to strings – backus Jul 28 '13 at 03:19
  • 5
    @Backus As well as objects and functions. – Kato Jul 28 '13 at 15:55
  • @SamuelNeff in a pinch, could be avoided by adding a toJSON on the object and do not return the reference. But I'd examine why we are making deep copies of instances with circular references? A clone method on the instance could be much more appropriate. – Kato Jul 29 '14 at 13:54
  • 2
    @Kato, Why would circular references imply there's no need to make deep copies? They're two unrelated things. It's certainly possible to write a good clone method for NodeJS that supports circular references and doesn't fall back on using JSON to clone. https://github.com/pvorb/node-clone – Samuel Neff Jul 29 '14 at 15:32
  • 1
    It doesn't imply it. But in practice, circular references occur on instantiated objects and complex structures, which should probably just provide a clone() method if they are going to be copied. – Kato Jul 29 '14 at 18:16
  • I really like this approach, but I've just come across another pitfall of this. Some objects (in my case `ObjectId`s in Mongo) don't get correctly copied by this approach, they get converted to strings instead. I'm guessing they're overriding `toString` or something similar. – Vala May 11 '15 at 15:05
  • bad implementation. for example, if my object contain a function, this will not work! – Yin Jul 07 '15 at 03:52
  • 2
    Already noted in the comments and in the description. You can't clone a function, object prototype, or other things you shouldn't be trying to do with a generic clone method. You'll need more than one line of code for that, and probably shouldn't be cloning that junk anyway--put a clone method on your class that knows how to handle the internals and do `newObj = obj.clone(args...);` – Kato Jul 07 '15 at 16:08
  • I have actually found that sometimes this is faster. I don't really understand why, but the JSON parser is pretty fast for JS standards. – Dillon Burnett Dec 23 '19 at 22:26
  • Not working for really big strings, you'll faced up error: RangeError: Invalid string length – Igor Benikov Aug 13 '21 at 08:58
  • As already mentioned, be careful with these kind of usage as explained here: https://medium.com/@pmzubar/why-json-parse-json-stringify-is-a-bad-practice-to-clone-an-object-in-javascript-b28ac5e36521 – Schlumpf Nov 30 '21 at 15:22
  • For anyone like me who preferred this answer because it didn't rely on external libraries or rolling your own, it's worth highlighting the new and not yet as popular answer by Jonathan Brizio below. Node 18 contains `structuredClone` as a global and has been LTS since 2022-10-25. (it's also in Node 17 but I figure most folks here looking for a simple, robust solution). It's effectively doing the same thing as the JSON round trip, but more efficiently. – MrCranky May 02 '23 at 08:56
  • From Node v17, you should use [structuredClone()](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone). – VladimirKosmala May 05 '23 at 19:57
45

Object.assign hasn't been mentioned in any of above answers.

let cloned = Object.assign({}, source);

If you're on ES6 you can use the spread operator:

let cloned = { ... source };

Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Sam G
  • 1,242
  • 15
  • 12
  • 48
    Note that both of these are shallow clones and the spread operator on objects requires node.js 8+. – jlh Oct 16 '17 at 09:33
  • 3
    As @jlh mentioned this is not going to work for nested objects. You can read more on deep clone issues of this method here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Deep_Clone – Shnd Oct 13 '18 at 17:44
  • 2
    As Shnd said, this answer is incorrect. For deep cloning, we need to use other alternatives because Object.assign() copies property values. If the source value is a reference to an object, it only copies that reference value. – troy Apr 15 '19 at 08:40
  • 2
    This does not clone, it just references the original object, meaning if you change something it will go to the master – Aidan Jul 30 '19 at 14:25
  • @AidanWelch I don't think that is correct. `let a = {x:1}; let b = Object.assign({}, a); a.x = 2; a.y = 1; console.log(a, b);` – pmiguelpinto90 Feb 11 '20 at 11:41
  • @MiguelPynto sorry you are correct, I meant it does not deep clone – Aidan Feb 11 '20 at 12:14
20

There are some Node modules out there if don't want to "roll your own". This one looks good: https://www.npmjs.com/package/clone

Looks like it handles all kinds of stuff, including circular references. From the github page:

clone masters cloning objects, arrays, Date objects, and RegEx objects. Everything is cloned recursively, so that you can clone dates in arrays in objects, for example. [...] Circular references? Yep!

pvorb
  • 7,157
  • 7
  • 47
  • 74
clint
  • 14,402
  • 12
  • 70
  • 79
12

You can use lodash as well. It has a clone and cloneDeep methods.

var _= require('lodash');

var objects = [{ 'a': 1 }, { 'b': 2 }];

var shallow = _.clone(objects);
console.log(shallow[0] === objects[0]);
// => true

var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
Michal
  • 3,218
  • 2
  • 25
  • 44
10

It's hard to do a generic but useful clone operation because what should be cloned recursively and what should be just copied depends on how the specific object is supposed to work.

Something that may be useful is

function clone(x)
{
    if (x === null || x === undefined)
        return x;
    if (typeof x.clone === "function")
        return x.clone();
    if (x.constructor == Array)
    {
        var r = [];
        for (var i=0,n=x.length; i<n; i++)
            r.push(clone(x[i]));
        return r;
    }
    return x;
}

In this code the logic is

  • in case of null or undefined just return the same (the special case is needed because it's an error to try to see if a clone method is present)
  • does the object have a clone method ? then use that
  • is the object an array ? then do a recursive cloning operation
  • otherwise just return the same value

This clone function should allow implementing custom clone methods easily... for example

function Point(x, y)
{
    this.x = x;
    this.y = y;

    ...
}

Point.prototype.clone = function()
{
    return new Point(this.x, this.y);
};



function Polygon(points, style)
{
    this.points = points;
    this.style = style;

    ...
}

Polygon.prototype.clone = function()
{
    return new Polygon(clone(this.points),
                       this.style);
};

When in the object you know that a correct cloning operation for a specific array is just a shallow copy then you can call values.slice() instead of clone(values).

For example in the above code I am explicitly requiring that a cloning of a polygon object will clone the points, but will share the same style object. If I want to clone the style object too instead then I can just pass clone(this.style).

6502
  • 112,025
  • 15
  • 165
  • 265
9

For a shallow copy, I like to use the reduce pattern (usually in a module or such), like so:

var newObject = Object.keys(original).reduce(function (obj, item) {
    obj[item] = original[item];
    return obj;
},{});

Here's a jsperf for a couple of the options: http://jsperf.com/shallow-copying

Olli K
  • 1,720
  • 1
  • 16
  • 17
9

There is no native method for cloning objects. Underscore implements _.clone which is a shallow clone.

_.clone = function(obj) {
  return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};

It either slices it or extends it.

Here's _.extend

// extend the obj (first parameter)
_.extend = function(obj) {
  // for each other parameter
  each(slice.call(arguments, 1), function(source) {
    // loop through all properties of the other objects
    for (var prop in source) {
      // if the property is not undefined then add it to the object.
      if (source[prop] !== void 0) obj[prop] = source[prop];
    }
  });
  // return the object (first parameter)
  return obj;
};

Extend simply iterates through all the items and creates a new object with the items in it.

You can roll out your own naive implementation if you want

function clone(o) {
  var ret = {};
  Object.keys(o).forEach(function (val) {
    ret[val] = o[val];
  });
  return ret;
}

There are good reasons to avoid deep cloning because closures cannot be cloned.

I've personally asked a question about deep cloning objects before and the conclusion I came to is that you just don't do it.

My recommendation is use underscore and it's _.clone method for shallow clones

Community
  • 1
  • 1
Raynos
  • 166,823
  • 56
  • 351
  • 396
9

In Node.js 17.x was added the method structuredClone() to allow made a deep clone.

Documentation of reference: https://developer.mozilla.org/en-US/docs/Web/API/structuredClone

Jonathan Brizio
  • 1,087
  • 1
  • 14
  • 28
8

Old question, but there's a more elegant answer than what's been suggested so far; use the built-in utils._extend:

var extend = require("util")._extend;

var varToCopy = { test: 12345, nested: { val: 6789 } };

var copiedObject = extend({}, varToCopy);

console.log(copiedObject);

// outputs:
// { test: 12345, nested: { val: 6789 } }

Note the use of the first parameter with an empty object {} - this tells extend that the copied object(s) need to be copied to a new object. If you use an existing object as the first parameter, then the second (and all subsequent) parameters will be deep-merge-copied over the first parameter variable.

Using the example variables above, you can also do this:

var anotherMergeVar = { foo: "bar" };

extend(copiedObject, { anotherParam: 'value' }, anotherMergeVar);

console.log(copiedObject);

// outputs:
// { test: 12345, nested: { val: 6789 }, anotherParam: 'value', foo: 'bar' }

Very handy utility, especially where I'm used to extend in AngularJS and jQuery.

Hope this helps someone else; object reference overwrites are a misery, and this solves it every time!

Scott Byers
  • 3,007
  • 2
  • 17
  • 14
  • 3
    Using _extend is now depreciated. Use Object.assign() instead: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign – MacroMan Jul 25 '18 at 10:17
2

I implemented a full deep copy. I believe its the best pick for a generic clone method, but it does not handle cyclical references.

Usage example:

parent = {'prop_chain':3}
obj = Object.create(parent)
obj.a=0; obj.b=1; obj.c=2;

obj2 = copy(obj)

console.log(obj, obj.prop_chain)
// '{'a':0, 'b':1, 'c':2} 3
console.log(obj2, obj2.prop_chain)
// '{'a':0, 'b':1, 'c':2} 3

parent.prop_chain=4
obj2.a = 15

console.log(obj, obj.prop_chain)
// '{'a':0, 'b':1, 'c':2} 4
console.log(obj2, obj2.prop_chain)
// '{'a':15, 'b':1, 'c':2} 4

The code itself:

This code copies objects with their prototypes, it also copy functions (might be useful for someone).

function copy(obj) {
  // (F.prototype will hold the object prototype chain)
  function F() {}
  var newObj;

  if(typeof obj.clone === 'function')
    return obj.clone()

  // To copy something that is not an object, just return it:
  if(typeof obj !== 'object' && typeof obj !== 'function' || obj == null)
    return obj;

  if(typeof obj === 'object') {    
    // Copy the prototype:
    newObj = {}
    var proto = Object.getPrototypeOf(obj)
    Object.setPrototypeOf(newObj, proto)
  } else {
    // If the object is a function the function evaluate it:
    var aux
    newObj = eval('aux='+obj.toString())
    // And copy the prototype:
    newObj.prototype = obj.prototype
  }

  // Copy the object normal properties with a deep copy:
  for(var i in obj) {
    if(obj.hasOwnProperty(i)) {
      if(typeof obj[i] !== 'object')
        newObj[i] = obj[i]
      else
        newObj[i] = copy(obj[i])
    }
  }

  return newObj;
}

With this copy I can't find any difference between the original and the copied one except if the original used closures on its construction, so i think its a good implementation.

I hope it helps

VinGarcia
  • 1,015
  • 12
  • 19
1

Depending on what you want to do with your cloned object you can utilize the prototypal inheritence mechanism of javascript and achieve a somewhat cloned object through:

var clonedObject = Object.create(originalObject);

Just remember that this isn't a full clone - for better or worse.

A good thing about that is that you actually haven't duplicated the object so the memory footprint will be low.

Some tricky things to remember though about this method is that iteration of properties defined in the prototype chain sometimes works a bit different and the fact that any changes to the original object will affect the cloned object as well unless that property has been set on itself also.

VoxPelli
  • 2,697
  • 1
  • 16
  • 22
  • 3
    This is so ridiculous dangerous and unlike a clone at all. `var a = {foo: "bar"}, b = Object.create(a); a.foo = "broken"; console.log(b.foo); // "broken";` – Mulan May 26 '14 at 21:06
  • @naomik:`b.foo = "working"; console.log(a.foo); // still "broken";` One of course has to be aware that changes in the original object will be reflected in the "clone" and that changes in the "clone" won't be reflected in the original object – but I wouldn't call it dangerous – it all depends on what you want to do with your clone – VoxPelli May 27 '14 at 07:40
  • @naomik: I am quite new to JS, so I'd like some precisions. The shallow clone proposed by olli-k and that you liked seem (IMHO, but I might be wrong) to have the same limitations than the solution proposed by voxpelli. The original and shallow close will also share the same "items", updating an item in the original will also impact the shallow clone. Or? – bmorin Jun 24 '15 at 08:02
  • @bmornin, if you use Olli K's technique, modifying the original object will *not* cause a change in the new object. – Mulan Jun 25 '15 at 17:32
  • 1
    @VoxPelli The whole purpose of a "clone" is to isolate changes from the original object, hence this method _is_ more dangerous. – Doug Oct 27 '15 at 20:31
1

Objects and Arrays in JavaScript use call by reference, if you update copied value it might reflect on the original object. To prevent this you can deep clone the object, to prevent the reference to be passed, using lodash library cloneDeep method run command

npm install lodash

const ld = require('lodash')
const objectToCopy = {name: "john", age: 24}
const clonedObject = ld.cloneDeep(objectToCopy)
  • Thanks really worked, it solved my issue with [Ref*] when I tried just spread object – Alex Mar 08 '23 at 08:28
0

Try this module for complex structures, developed especially for nodejs - https://github.com/themondays/deppcopy

Works faster than JSON stringify and parse on large structures and supports BigInt.

  • Excessive promotion of a specific product/resource may be perceived by the community as **spam**. Take a look at the [help], specially [What kind of behavior is expected of users?](//stackoverflow.com/help/behavior)'s last section: _Avoid overt self-promotion_. You might also be interested in [How to not be a spammer](//stackoverflow.com/help/promotion) and [How do I advertise on Stack Overflow?](//www.stackoverflowbusiness.com/advertising). – Adrian Mole Feb 06 '23 at 11:14
-1

for array, one can use

var arr = [1,2,3]; 
var arr_2 = arr ; 

print ( arr_2 ); 

arr=arr.slice(0);

print ( arr ); 

arr[1]=9999; 

print ( arr_2 ); 
tlqtangok
  • 63
  • 1
  • 5
-1

How about this method

const v8 = require('v8');
const structuredClone = obj => {
  return v8.deserialize(v8.serialize(obj));
};