This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to clone js object?
This is another way to create a javascript object (using object literal notation instead of function):
user = {
name: "Foo",
email: "bar#baz.com"
}
Is there a way to clone this object or is it a singleton?
Try this:
var clone = (function(){
return function (obj) { Clone.prototype=obj; return new Clone() };
function Clone(){}
}());
Here's what's going on.
Clone is a dummy constructor.
We assign the object we want to clone to the Clone constructor's prototype.
We call Clone using 'new', so the constructed object has the original object as its constructor's prototype aka (non-standard) __proto__.
The cloned object will share all the properties of the original object without any copies of anything being made. If properties of the cloned object are assigned new values, they won't interfere with the original object. And no tampering of built-ins is required.
Keep in mind that an object property of the newly-created object will refer to the same object as the eponymous property of the cloned object. Assigning a new value to a property of the clone won't interfere with the original, but assigning values to the clone's object properties will.
Try this in chrome or firebug console:
var user = {
name: "Foo",
email: "bar#baz.com"
}
var clonedUser = clone(user);
console.dir(clonedUser);
A detailed explanation of this cloning technique can be found here.
You can use JSON object (present in modern browsers):
var user = {name: "Foo", email: "bar#baz.com" }
var user2 = JSON.parse(JSON.stringify(user))
user2.name = "Bar";
alert(user.name + " " + user2.name); // Foo Bar
See in jsfiddle.
EDIT
If you need this in older browsers, see http://www.json.org/js.html.
I like to use this:
if (typeof Object.create !== 'function') {
Object.create = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};
}
then any object I want to clone can be done as:
user = {
name: "Foo",
email: "bar#baz.com"
};
var user2 = Object.create(user);
As shown in (or similar to) JavaScript The Good Parts
Most of the javascript frameworks have good support for object cloning.
var a= {'key':'value'};
var b= jQuery.extend( true, {}, a );
Object.prototype.clone = function clone(obj) {
obj = obj || this;
var new_obj = {};
for( var p in obj ) {
if ( obj.hasOwnProperty(p) ) {
if( obj[p] !== null && typeof(obj[p]) === "object" ) {
new_obj[p] = clone( obj[p] );
}
else {
new_obj[p] = obj[p];
}
}
}
return new_obj;
};
/* Example */
var foo = {
name: "Foo"
, email: "bar#baz.com"
, obj: {a:"A",b:"B"}
};
var bar = foo.clone();
bar.name = "Bar";
bar.obj.b = "C";
// foo and bar should have a different 'name'
// foo and bar should retain the same email
// foo and bar should have different values for <foo/bar>['obj']['b']
// foo and bar should have the same values for <foo/bar>['obj']['a']
console.dir(foo);
console.dir(bar);
Related
Googling for "javascript clone object" brings some really weird results, some of them are hopelessly outdated and some are just too complex, isn't it as easy as just:
let clone = {...original};
Is there anything wrong with this?
This is good for shallow cloning. The object spread is a standard part of ECMAScript 2018.
For deep cloning you'll need a different solution.
const clone = {...original} to shallow clone
const newobj = {...original, prop: newOne} to immutably add another prop to the original and store as a new object.
EDIT: When this answer was posted, {...obj} syntax was not available in most browsers. Nowadays, you should be fine using it (unless you need to support IE 11).
Use Object.assign.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
However, this won't make a deep clone. There is no native way of deep cloning as of yet.
EDIT: As #Mike 'Pomax' Kamermans mentioned in the comments, you can deep clone simple objects (ie. no prototypes, functions or circular references) using JSON.parse(JSON.stringify(input))
If the methods you used isn't working well with objects involving data types like Date, try this
Import _
import * as _ from 'lodash';
Deep clone object
myObjCopy = _.cloneDeep(myObj);
You can do it like this as well,
let copiedData = JSON.parse(JSON.stringify(data));
if you don't want to use json.parse(json.stringify(object)) you could create recursively key-value copies:
function copy(item){
let result = null;
if(!item) return result;
if(Array.isArray(item)){
result = [];
item.forEach(element=>{
result.push(copy(element));
});
}
else if(item instanceof Object && !(item instanceof Function)){
result = {};
for(let key in item){
if(key){
result[key] = copy(item[key]);
}
}
}
return result || item;
}
But the best way is to create a class that can return a clone of it self
class MyClass{
data = null;
constructor(values){ this.data = values }
toString(){ console.log("MyClass: "+this.data.toString(;) }
remove(id){ this.data = data.filter(d=>d.id!==id) }
clone(){ return new MyClass(this.data) }
}
Following on from the answer by #marcel I found some functions were still missing on the cloned object. e.g.
function MyObject() {
var methodAValue = null,
methodBValue = null
Object.defineProperty(this, "methodA", {
get: function() { return methodAValue; },
set: function(value) {
methodAValue = value || {};
},
enumerable: true
});
Object.defineProperty(this, "methodB", {
get: function() { return methodAValue; },
set: function(value) {
methodAValue = value || {};
}
});
}
where on MyObject I could clone methodA but methodB was excluded. This occurred because it is missing
enumerable: true
which meant it did not show up in
for(let key in item)
Instead I switched over to
Object.getOwnPropertyNames(item).forEach((key) => {
....
});
which will include non-enumerable keys.
I also found that the prototype (proto) was not cloned. For that I ended up using
if (obj.__proto__) {
copy.__proto__ = Object.assign(Object.create(Object.getPrototypeOf(obj)), obj);
}
PS: Frustrating that I could not find a built in function to do this.
structured Clone
you can Used this method
function Copy_Object(obj) { return structuredClone(obj); }
We can do that with two way:
1- First create a new object and replicate the structure of the existing one by iterating
over its properties and copying them on the primitive level.
let user = {
name: "John",
age: 30
};
let clone = {}; // the new empty object
// let's copy all user properties into it
for (let key in user) {
clone[key] = user[key];
}
// now clone is a fully independant clone
clone.name = "Pete"; // changed the data in it
alert( user.name ); // still John in the original object
2- Second we can use the method Object.assign for that
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// copies all properties from permissions1 and permissions2 into user
Object.assign(user, permissions1, permissions2);
-Another example
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
It copies all properties of user into the empty object and returns it. Actually, the same as the loop, but shorter.
But Object.assign() not create a deep clone
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
let clone = Object.assign({}, user);
alert( user.sizes === clone.sizes ); // true, same object
// user and clone share sizes
user.sizes.width++; // change a property from one place
alert(clone.sizes.width); // 51, see the result from the other one
To fix that, we should use the cloning loop that examines each value of user[key] and, if it’s an object, then replicate its structure as well. That is called a “deep cloning”.
There’s a standard algorithm for deep cloning that handles the case above and more complex cases, called the Structured cloning algorithm.
In order not to reinvent the wheel, we can use a working implementation of it from the JavaScript library lodash the method is called _.cloneDeep(obj).
I found a solution which seems to copy functions as well, correct me if this example is an error.
Attention I have not tested this method with more complex object cases, which, for example, would include methods with this for reference
Take for example the price of a breakfast, I have this price available globally but I would like to adjust it individually for a hotel room
// make an object for a booking option
var opt_resa = { breakfast_val: 900 }
// i define a function for opt_resa :
opt_resa.func = function(){ alert('i am a function'); }
// copy object in modif.opt_resa :
var modif = { opt_resa : {} }
for ( var v in opt_resa ){
modif.opt_resa[v] = opt_resa[v];
}
// test
modif.opt_resa.breakfast_val = 1500;
// old value
console.log( opt_resa.breakfast_val );
// output : 900
// modified value
console.log( modif.opt_resa.breakfast_val );
// output : 1500
// function copied
modif.opt_resa.func();
// this function works
All the methods above do not handle deep cloning of objects where it is nested to n levels. I did not check its performance over others but it is short and simple.
The first example below shows object cloning using Object.assign which clones just till first level.
var person = {
name:'saksham',
age:22,
skills: {
lang:'javascript',
experience:5
}
}
newPerson = Object.assign({},person);
newPerson.skills.lang = 'angular';
console.log(newPerson.skills.lang); //logs Angular
Using the below approach deep clones object
var person = {
name:'saksham',
age:22,
skills: {
lang:'javascript',
experience:5
}
}
anotherNewPerson = JSON.parse(JSON.stringify(person));
anotherNewPerson.skills.lang = 'angular';
console.log(person.skills.lang); //logs javascript
Googling for "javascript clone object" brings some really weird results, some of them are hopelessly outdated and some are just too complex, isn't it as easy as just:
let clone = {...original};
Is there anything wrong with this?
This is good for shallow cloning. The object spread is a standard part of ECMAScript 2018.
For deep cloning you'll need a different solution.
const clone = {...original} to shallow clone
const newobj = {...original, prop: newOne} to immutably add another prop to the original and store as a new object.
EDIT: When this answer was posted, {...obj} syntax was not available in most browsers. Nowadays, you should be fine using it (unless you need to support IE 11).
Use Object.assign.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
However, this won't make a deep clone. There is no native way of deep cloning as of yet.
EDIT: As #Mike 'Pomax' Kamermans mentioned in the comments, you can deep clone simple objects (ie. no prototypes, functions or circular references) using JSON.parse(JSON.stringify(input))
If the methods you used isn't working well with objects involving data types like Date, try this
Import _
import * as _ from 'lodash';
Deep clone object
myObjCopy = _.cloneDeep(myObj);
You can do it like this as well,
let copiedData = JSON.parse(JSON.stringify(data));
if you don't want to use json.parse(json.stringify(object)) you could create recursively key-value copies:
function copy(item){
let result = null;
if(!item) return result;
if(Array.isArray(item)){
result = [];
item.forEach(element=>{
result.push(copy(element));
});
}
else if(item instanceof Object && !(item instanceof Function)){
result = {};
for(let key in item){
if(key){
result[key] = copy(item[key]);
}
}
}
return result || item;
}
But the best way is to create a class that can return a clone of it self
class MyClass{
data = null;
constructor(values){ this.data = values }
toString(){ console.log("MyClass: "+this.data.toString(;) }
remove(id){ this.data = data.filter(d=>d.id!==id) }
clone(){ return new MyClass(this.data) }
}
Following on from the answer by #marcel I found some functions were still missing on the cloned object. e.g.
function MyObject() {
var methodAValue = null,
methodBValue = null
Object.defineProperty(this, "methodA", {
get: function() { return methodAValue; },
set: function(value) {
methodAValue = value || {};
},
enumerable: true
});
Object.defineProperty(this, "methodB", {
get: function() { return methodAValue; },
set: function(value) {
methodAValue = value || {};
}
});
}
where on MyObject I could clone methodA but methodB was excluded. This occurred because it is missing
enumerable: true
which meant it did not show up in
for(let key in item)
Instead I switched over to
Object.getOwnPropertyNames(item).forEach((key) => {
....
});
which will include non-enumerable keys.
I also found that the prototype (proto) was not cloned. For that I ended up using
if (obj.__proto__) {
copy.__proto__ = Object.assign(Object.create(Object.getPrototypeOf(obj)), obj);
}
PS: Frustrating that I could not find a built in function to do this.
structured Clone
you can Used this method
function Copy_Object(obj) { return structuredClone(obj); }
We can do that with two way:
1- First create a new object and replicate the structure of the existing one by iterating
over its properties and copying them on the primitive level.
let user = {
name: "John",
age: 30
};
let clone = {}; // the new empty object
// let's copy all user properties into it
for (let key in user) {
clone[key] = user[key];
}
// now clone is a fully independant clone
clone.name = "Pete"; // changed the data in it
alert( user.name ); // still John in the original object
2- Second we can use the method Object.assign for that
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// copies all properties from permissions1 and permissions2 into user
Object.assign(user, permissions1, permissions2);
-Another example
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
It copies all properties of user into the empty object and returns it. Actually, the same as the loop, but shorter.
But Object.assign() not create a deep clone
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
let clone = Object.assign({}, user);
alert( user.sizes === clone.sizes ); // true, same object
// user and clone share sizes
user.sizes.width++; // change a property from one place
alert(clone.sizes.width); // 51, see the result from the other one
To fix that, we should use the cloning loop that examines each value of user[key] and, if it’s an object, then replicate its structure as well. That is called a “deep cloning”.
There’s a standard algorithm for deep cloning that handles the case above and more complex cases, called the Structured cloning algorithm.
In order not to reinvent the wheel, we can use a working implementation of it from the JavaScript library lodash the method is called _.cloneDeep(obj).
I found a solution which seems to copy functions as well, correct me if this example is an error.
Attention I have not tested this method with more complex object cases, which, for example, would include methods with this for reference
Take for example the price of a breakfast, I have this price available globally but I would like to adjust it individually for a hotel room
// make an object for a booking option
var opt_resa = { breakfast_val: 900 }
// i define a function for opt_resa :
opt_resa.func = function(){ alert('i am a function'); }
// copy object in modif.opt_resa :
var modif = { opt_resa : {} }
for ( var v in opt_resa ){
modif.opt_resa[v] = opt_resa[v];
}
// test
modif.opt_resa.breakfast_val = 1500;
// old value
console.log( opt_resa.breakfast_val );
// output : 900
// modified value
console.log( modif.opt_resa.breakfast_val );
// output : 1500
// function copied
modif.opt_resa.func();
// this function works
All the methods above do not handle deep cloning of objects where it is nested to n levels. I did not check its performance over others but it is short and simple.
The first example below shows object cloning using Object.assign which clones just till first level.
var person = {
name:'saksham',
age:22,
skills: {
lang:'javascript',
experience:5
}
}
newPerson = Object.assign({},person);
newPerson.skills.lang = 'angular';
console.log(newPerson.skills.lang); //logs Angular
Using the below approach deep clones object
var person = {
name:'saksham',
age:22,
skills: {
lang:'javascript',
experience:5
}
}
anotherNewPerson = JSON.parse(JSON.stringify(person));
anotherNewPerson.skills.lang = 'angular';
console.log(person.skills.lang); //logs javascript
The code below does what I want, but I would like to avoid eval. Is there a function in Javascript that looks up an object by its name as defined by in a string?
myobject = {"foo" : "bar"}
myname = "myobject";
eval(myname);
Some context: I am using this for an application in which a large number of nodes in the dom has a html5 data-object attribute, which is used in the handler function to connect back to the model.
Edit: myobject is neither global nor local, it is defined in one of the parent frames of the handler.
If variables are global then:
myobject = {"foo" : "bar"};
myname = "myobject";
window[myname].foo
DEMO
For local:
(function(){
myobject = {"foo" : "bar"};
myname = "myobject";
alert( this[myname].foo );
})();
DEMO
Local Variable Solution:
You could make all objects that you want to access with a string properties of another object. For example:
var objectHolder = {
myobject: {"foo" : "bar"},
myobject2: {"foo" : "bar"},
myobject3: {"foo" : "bar"}
};
And then access your desired object like this:
var desiredObject = objectHolder["myobject"];
Global Variable Solution:
You can access global variables using a string like this:
window["myobject"];
This question is pretty old, but since it's the top result on Google for the query "javascript get object from string", I thought I'd share a technique for longer object paths using dot notation.
Given the following:
var foo = { 'bar': { 'alpha': 'beta' } };
We can get the value of 'alpha' from a string like this:
var objPath = "bar.alpha";
var alphaVal = objPath.split('.')
.reduce(function (object, property) {
return object[property];
}, foo);
// alphaVal === "beta"
If it's global:
window.foo = { 'bar': { 'alpha': 'beta' } };
Just pass window as the initialValue for reduce:
var objPath = "foo.bar.alpha";
var alphaVal = objPath.split('.')
.reduce(function (object, property) {
return object[property];
}, window);
// alphaVal === "beta"
Basically we can use reduce to traverse object members by passing in the initial object as the initialValue.
MDN article for Array.prototype.reduce
since window is a global namespace, you could simply use
window[myname]
We use a fair bit of dotted notation variable structures. Needed a way to traverse them without erroring on undefined, and return value or undefined as the answer. Hope this helps.
function getValueOrUndefined(id) {
let parent = window;
if (id.indexOf(".") !== -1) {
let current = null;
let child = undefined;
let names = id.split(".");
for (let i = 0; i < names.length; i++) {
current = names[i];
child = parent[current];
if (child === undefined)
return child;
else
parent = child;
}
return child;
}
return parent[id];
}
I'm going to be getting an array of objects and want to set instance variables inside of a class based on a property. So if I get this:
ary = [{type: 'walrus', name: 'GorbyPuff'}, {type: 'humanoid', occupation: 'KingSlayer'}]
I want to initialize an object where #walrus == ary[0] and #humanoid == ary[1]
In Ruby I could user instance_variable_set, but how can this be accomplished in the Javascripts?
I'm not sure if I get what you're trying to acchieve, but the easiest way to do this would be:
var theObj = {};
for(var i=0;i<ary.length;i++)
{
theObj[ary[i].type] = ary[i];
}
The worry here is, that by altering the ary variable you will inadvertently alter the theObj:
console.log(theObj.walrus.name);//Outputs: GorbyPuff
ary[0].name = 'Nips!';
console.log(theObj.walrus.name);//Outputs: Nips! <-- objects are passed by reference, always
If the ary variable is part of a function scope, and the resulting object is its return value, you needn't worry. But if both are part of the global scope (Which they shouldn't, it's bad practice), this becomes an issue.
I therefore propose this approach:
var obj = {};
var i;
while (ary.length !== 0)
{
i = ary.splice(0,1)[0];//removes element from array
if (i.hasOwnProperty('type'))//always best to check the property you're going to use is there
{
obj[i.type] = i;
}
}
There's nothing in JS that can do this for you, just do a loop to build the object you want:
ary = [{type: 'walrus', name: 'GorbyPuff'}, {type: 'humanoid', occupation: 'KingSlayer'}]
instances={}
for(x=0;x<ary.length;x++) instances[ary[x].type]=ary[x]
document.write(instances.walrus.name) //GorbyBuff
document.write(instances.humanoid.occupation) //KingSlayer
If you want to use that array of objects as prototypes, you can do this:
var Walrus = function(){};
Walrus.prototype=ary[0];
var aWalrus = new Walrus(); // creates a new Walrus. aWalrus.name => GorbyPuff
In Javascript the Good Parts, Douglas Crawford describes a more general way of doing it:
if (typeof Object.create !== 'function') {
Object.create = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};
}
Which you can use like this:
var aWalrus = Object.create(ary[0]);
here is a example of what you want:
// the class:
function MyClass(){
// stuff
}
// the data object
var o = [
{type:"MyClass",name:"a name"}
]
// how to instantiate:
var instances = [];
for(var i=0;i<o.length;i++){
if(typeof this[o[i].type] == "function")
instances.push(new this[o[i].type](o[i].name))
}
If you create the classes in a function you need to use "this" as a reference to that function, else you can use "window"
I have a object literal:
var obj = {
a : document.getElementById("ex1"),
b : obj.a.document.getElementsByTagName("div")
};
I am having trouble with the b property, for some reason it is not letting that happen. Is this possible?
The modern way to do this is with getter methods:
let obj = {
firstName: "A’dab",
lastName: "Farooqi"
get fullName() {
return this.firstName+" "+this.lastName;
},
}
So now you can just write obj.fullName - no need for the parentheses on the end.
You need two steps:
var obj = {
a : document.getElementById("ex1")
};
obj.b = obj.a.document.getElementsByTagName("div")
Or:
var temp = document.getElementById("ex1")
var obj = {
a : temp,
b : temp.document.getElementsByTagName("div")
};
When the property b is being defined, obj is not defined yet. One way to get around that problem is to make your property a function so that it's not evaluated until called.
var obj = {
a : document.getElementById("ex1"),
b : function() {
// This is not evaluated until obj.b() is called
return obj.a.document.getElementsByTagName("div");
}
};
obj.b();
If you really want it to be a property, you have to do it in two steps as Tomasz Nurkiewicz shows