I have a JavaScript array of objects, which is initialised with some values.
I want to copy those values to a new array of objects, but without referencing to the original one, so I can then manipulate the new object.
I tried objectOptions.concat() like in this sample code but it then deletes also the referenced original object:
var objectOptions = [{option1: 'value1', someOption: 'value2'}];
function objectClean(){
var newObjectOptions = objectOptions.concat();
for(var i in newObjectOptions ) {
delete newObjectOptions[i]['someOption'];
}
return newObjectOptions ;
};
If your object is simple enough and JSON-compatible (i.e., only contains objects, arrays and primitives, no DOM references, no Regex objects, no circular references etc.), the simplest way to clone is:
var clone = JSON.parse(JSON.stringify(original));
Otherwise, you'll need a deep copy function, like the one found on this answer*:
function clone(obj){
if(obj == null || typeof(obj) != 'object')
return obj;
var temp = obj.constructor(); // changed
for(var key in obj)
temp[key] = clone(obj[key]);
return temp;
}
* Be careful! The accepted answer to that question is a jQuery only solution, and terribly overrated!
var copyme = {/*object with properties which are to be copied in another object*/};
var copy = {};
for (var attr in copyme) {
if (copyme.hasOwnProperty(attr)) copy[attr] = clone(copyme[attr]);
}
Related
I am referring to this answered question Convert Array into Object. Specifically the answer of #JVE999. Since my reputaion is too low to comment on the answer I am asking a new question.
I don't understand this piece of code. It works like a charm in my code but I simply don't understand why. Could I get a brief walkthrough what each line does and how it actually converts an array into an object?
var convArrToObj = function(array){
var thisEleObj = new Object();
if(typeof array == "object"){
for(var i in array){
var thisEle = convArrToObj(array[i]);
thisEleObj[i] = thisEle;
}
}else {
thisEleObj = array;
}
return thisEleObj;
}
Because I'm not sure what you know or don't know, so I'll try to explain every line:
var convArrToObj = function(array){ defines a function with a single parameter, array.
var thisEleObj = new Object(); initializes a new object using a constructor function. var thisEleObj = {}; also works.
if(typeof array == "object"){ ensures that the input is an array or an object. It's not strictly necessary if you know that the input will be an array or an object and that you will not need recursion (see line 5).
for(var i in array){ loops through each "key" in the object. In an array, the keys are all numerical and in numerical order, so for(var i=0;i<array.length;i++){ would be a similar version that only supports arrays.
var thisEle = convArrToObj(array[i]); This is the clever part, and likely the most unclear. It checks if the target property of the object (or index of the array) is an array itself, and copies it as an object if so.
thisEleObj[i]=thisEle is the part that "gets everything done" by copying thisEle(the converted array) to the array.
else { thisEleObj=array} doesn't bother to process datatypes like numbers (who usually don't have properties) or functions (who have properties that should not be processed)
return thisEleObj outputs the processed object to an assignment/another function/another call of itself due to recursion.
Hope this helped, tell me if there's anything I need to clarify.
May it can help you :)
var convArrToObj = function(array){
var thisEleObj = new Object();
// when first time it checks for type [1, 2, 3, 4] it return object because type of a object return object
if(typeof array == "object"){
for(var i in array){
// here we are getting each item from array and calling same function convArrToObj(1) and this time will not be object so if condition get false and return same value from else { thisEleObj = array; } and this value will assigned to a index of object
var thisEle = convArrToObj(array[i]);
thisEleObj[i] = thisEle;
}
}else {
thisEleObj = array;
}
//and finaly thisEleObj will be object when recursive function get called variables inside function creates new scope so thisEleObj will not be override each time. In last when array finished loop final object will be returned yoc can check console()
console.log(thisEleObj);
return thisEleObj;
}
convArrToObj([1, 2, 3, 4]);
This question already has answers here:
Crockford's Prototypal inheritance - Issues with nested objects
(3 answers)
Closed 7 years ago.
I am trying to understand how Object.create copies arrays and objects properties when initiating a new object. It seems to be different then copying a string or number. For example if we have a basic Object with a number and array property. jsfiddle example
var obj = {
num: 0, arr: []
};
We then initiate 3 new Objects from this base.
var set1 = Object.create(obj);
set1.num = 10;
set1.arr.push(1);
var set2 = Object.create(obj);
var set3 = Object.create(obj, {arr: []});
I was expecting set2.num and set2.arr property to be it's initial state. I found this to be true for the number, but not the array. Of course one work around is to pass {arr: []} when initiating the Object or creating a initiation function that resets the arr property.
// false
console.log(set1.num === set2.num);
// true - why is this true???
console.log(set1.arr === set2.arr);
// false
console.log(set1.arr === set3.arr);
Is this the normal behavior? Is Object.create keeping a reference to all of the Object's array and object properties? It would be very nice to not have to create new arrays and objects when initiating a new Object.
It would be very nice to not have to create new arrays and objects when initiating a new Object
Write a function in your favourite style
Returning a literal
function makeMyObject() {
return {num: 0, arr: []};
}
// usage
var obj = MyObject();
Returning an Object.created object, and assigning to it,
function makeMyObject() {
var o = Object.create(null); // or some prototype instead of `null`
return Object.assign(o, {num: 0, arr: []});
}
// usage
var obj = MyObject();
Using new
function MyObject() {
this.num = 0;
this.arr = [];
}
// usage
var obj = new MyObject();
Cloning is a bit more complicated, a basic example might be
function shallowClone(o) {
var e;
if (typeof o !== 'object')
return o;
e = Object.create(Object.getPrototypeOf(o));
// copy enumerable references
Object.assign(e, o);
// or to keep non-enumerable properties
// Object.defineProperties(b, Object.getOwnPropertyNames(o).map(Object.getOwnPropertyDescriptor.bind(Object, o)));
return e;
}
Deep cloning requires looping over properties (e.g. for..in for enumerable only) and type checking instead of simply copying everything over. You usually end up needing to recurse on properties which are Objects themselves.
For known types, you can teach it to use the correct constructor too, e.g.
if (Array.isArray(o)) {
e = [];
o.forEach((v, i) => e[i] = recurse(v));
}
Where recurse would be the name of the clone function
This question already has answers here:
Shallow-clone a Map or Set
(6 answers)
What is the most efficient way to deep clone an object in JavaScript?
(67 answers)
Closed 2 years ago.
How do I clone/copy a Map in JavaScript?
I know how to clone an array, but how do I clone/copy a Map?
var myArray = new Array(1, 2, 3);
var copy = myArray.slice();
// now I can change myArray[0] = 5; & it wont affect copy array
// Can I just do the same for map?
var myMap = new ?? // in javascript is it called a map?
var myMap = {"1": 1, "2", 2};
var copy = myMap.slice();
With the introduction of Maps in JavaScript it's quite simple considering the constructor accepts an iterable:
var newMap = new Map(existingMap)
Documentation here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
A simple way (to do a shallow copy) is to copy each property of the source map to the target map:
var newMap = {};
for (var i in myMap)
newMap[i] = myMap[i];
NOTE: newMap[i] could very well be a reference to the same object as myMap[i]
Very simple to just use Object.assign()
let map = {'a': 1, 'b': 2}
let copy = Object.assign({}, map);
// Or
const copy = Object.assign({}, {'a': 1, 'b': 2});
JQuery has a method to extend an object (merging two objects), but this method can also be used to clone an object by providing an empty object.
// Shallow copy
var newObject = jQuery.extend({}, oldObject);
// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);
More information can be found in the jQuery documentation.
If you need to make a deep copy of a Map you can use the following:
new Map(JSON.parse(JSON.stringify(Array.from(source))));
Where source is the original Map object.
Note this may not be suitable for all use cases where the Map values are not serializable, for more details see: https://stackoverflow.com/a/122704/10583071
There is nothing built in.
Either use a well tested recursive property copier or if performance isn't an issue, serialise to JSON and parse again to a new object.
There is no built-in (edit: DEEP) clone/copy. You can write your own method to either shallow or deep copy:
function shallowCopy(obj) {
var result = {};
for (var i in obj) {
result[i] = obj[i];
}
return result;
}
function deepCopy(obj) {
var result = {};
for (var i in obj) {
// recursion here, though you'll need some non-trivial logic
// to avoid getting into an endless loop.
}
return result;
}
[EDIT] Shallow copy is built-in, using Object.assign:
let result = Object.assign({}, obj);
All objects in Javascript are dynamic, and can be assigned new properties. A "map" as you refer to it is actually just an empty object. An Array is also an object, with methods such as slice and properties like length.
I noticed that Map should require special treatment, thus with all suggestions in this thread, code will be:
function deepClone( obj ) {
if( !obj || true == obj ) //this also handles boolean as true and false
return obj;
var objType = typeof( obj );
if( "number" == objType || "string" == objType ) // add your immutables here
return obj;
var result = Array.isArray( obj ) ? [] : !obj.constructor ? {} : new obj.constructor();
if( obj instanceof Map )
for( var key of obj.keys() )
result.set( key, deepClone( obj.get( key ) ) );
for( var key in obj )
if( obj.hasOwnProperty( key ) )
result[key] = deepClone( obj[ key ] );
return result;
}
If I clone an array, I use cloneArr = arr.slice()
I want to know how to clone an object in nodejs.
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.
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
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!
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]);
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).
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
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
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!
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
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
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.
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)
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.
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 );
How about this method
const v8 = require('v8');
const structuredClone = obj => {
return v8.deserialize(v8.serialize(obj));
};
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the most efficient way to clone a JavaScript object?
How to clone js object with out reference like these:
{ ID: _docEl,
Index: next,
DocName: _el
}
Any ideas?
Edit: New visitors should probably head to this question. There is a new (as of this writing) browser supported function called structuredClone() that will be useful as browsers and engines adopt it.
Still consider the additional considerations I write below:
You'll have to iterate over the object and make copies of all its properties.
And then if any of its properties are also objects, assuming you want to clone those too, you'll have to recurse into them.
There's various methods for doing this here:
What is the most efficient way to clone a JavaScript object?
Doing this isn't a perfect copy - depending on how it's done the new object won't inherit the original object's relationship to its prototype and you won't be able to maintain the same distinction between copied properties that were from the prototypal chain or from the object itself. And built-in objects (like DOM nodes) won't copy properly. In the case of DOM nodes you can clone those with their own cloneNode().
Additional considerations
Consider whether your application really needs to clone the object or whether some other design might be appropriate.
Cloning an object by copying all its properties will create two separate copies of all its properties, and if you modify one's properties the other object won't change. If you don't need this to be the case, simply copying the object will suffice.
You can also consider using prototypes (or the newer class syntax) and new which effectively creates objects with a set of properties from a prototype that can be overridden naturally or have fall-back to those in the prototype.
Or, finally, if you wanted to add properties or methods to the new object without affecting the original object, can you just encapsulate object A into object B, that is, have object A as a property in object B, so that you can still get the reference to the original object as b.a.property, but can add properties to b alone as b.property.
Here's how I'd do it, based on thomasrutter's suggestion (untested code):
function cloneObj(obj) {
var clone = {};
for (var i in obj) {
if (obj[i] && typeof obj[i] == 'object') {
clone[i] = cloneObj(obj[i]);
} else {
clone[i] = obj[i];
}
}
return clone;
}
You can use jQuery.extend:
// Shallow copy
var newObject = jQuery.extend({}, oldObject);
// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);
The following post is so helpful:
What is the most efficient way to deep clone an object in JavaScript?
JavaScript JS object clone
Object._clone = function(obj) {
var clone, property, value;
if (!obj || typeof obj !== 'object') {
return obj;
}
clone = typeof obj.pop === 'function' ? [] : {};
clone.__proto__ = obj.__proto__;
for (property in obj) {
if (obj.hasOwnProperty(property)) {
value = obj.property;
if (value && typeof value === 'object') {
clone[property] = Object._clone(value);
} else {
clone[property] = obj[property];
}
}
}
return clone;
};
CoffeeScript JS object clone
# Object clone
Object._clone = (obj) ->
return obj if not obj or typeof(obj) isnt 'object'
clone = if typeof(obj.pop) is 'function' then [] else {}
# deprecated, but need for instanceof method
clone.__proto__ = obj.__proto__
for property of obj
if obj.hasOwnProperty property
# clone properties
value = obj.property
if value and typeof(value) is 'object'
clone[property] = Object._clone(value)
else
clone[property] = obj[property]
clone
Now you can try to do that
A = new TestKlass
B = Object._clone(A)
B instanceof TestKlass => true
function objToClone(obj){
return (new Function("return " + obj))
}