I have a big object with much data. And i want to clone this in other variable. When i set some param of the instance B has the same result in the original object:
var obj = {a: 25, b: 50, c: 75};var A = obj;var B = obj;A.a = 30;B.a = 40;alert(obj.a + " " + A.a + " " + B.a); // 40 40 40
My output should be 25 30 40.Any ideas?
EDIT
Thanks Everyone. I change the code of dystroy and this is my result:
Object.prototype.clone = Array.prototype.clone = function() {if (Object.prototype.toString.call(this) === '[object Array]') {var clone = [];for (var i = 0; i < this.length; i++)clone[i] = this[i].clone();return clone;} else if (typeof(this) === "object") {var clone = {};for (var prop in this) {if (this.hasOwnProperty(prop))clone[prop] = this[prop].clone();}return clone;} else {return this;}}var obj = {a: 25, b: 50, c: 75};var A = obj.clone();var B = obj.clone();A.a = 30;B.a = 40;alert(obj.a + " " + A.a + " " + B.a);var arr = [25, 50, 75];var C = arr.clone();var D = arr.clone();C[0] = 30;D[0] = 40;alert(arr[0] + " " + C[0] + " " + D[0]);
Best Answer
If you use an =
statement to assign a value to a var
with an object on the right side, javascript will not copy but reference the object.
Spoiler : using JSON.parse(JSON.stringify(obj))
may work but is costly, and might throw a TypeError
as in
const a = {};const b = { a };a.b = b;const clone = JSON.parse(JSON.stringify(a));/* ThrowsUncaught TypeError: Converting circular structure to JSON--> starting at object with constructor 'Object'| property 'b' -> object with constructor 'Object'--- property 'a' closes the circleat JSON.stringify (<anonymous>)at <anonymous>:4:6*/
As of es2015, if you want a shallow copy (clone the object, but keeping deep refences in the inner structure) you can use destructuring :
const obj = { foo: { bar: "baz" } };const shallowClone = { ...obj };
shallowClone
is a new object, but shallowClone.foo
holds a reference to the same object as obj.foo
.
You can use lodash's clone
method, which does the same, if you don't have access to the spread operator.
var obj = {a: 25, b: 50, c: 75};var A = _.clone(obj);
Or lodash's cloneDeep
method if your object has multiple object levels
var obj = {a: 25, b: {a: 1, b: 2}, c: 75};var A = _.cloneDeep(obj);
Or lodash's merge
method if you mean to extend the source object
var obj = {a: 25, b: {a: 1, b: 2}, c: 75};var A = _.merge({}, obj, {newkey: "newvalue"});
Or you can use jQuerys extend
method:
var obj = {a: 25, b: 50, c: 75};var A = $.extend(true,{},obj);
Here is jQuery 1.11 extend method's source code :
jQuery.extend = jQuery.fn.extend = function() {var src, copyIsArray, copy, name, options, clone,target = arguments[0] || {},i = 1,length = arguments.length,deep = false;// Handle a deep copy situationif ( typeof target === "boolean" ) {deep = target;// skip the boolean and the targettarget = arguments[ i ] || {};i++;}// Handle case when target is a string or something (possible in deep copy)if ( typeof target !== "object" && !jQuery.isFunction(target) ) {target = {};}// extend jQuery itself if only one argument is passedif ( i === length ) {target = this;i--;}for ( ; i < length; i++ ) {// Only deal with non-null/undefined valuesif ( (options = arguments[ i ]) != null ) {// Extend the base objectfor ( name in options ) {src = target[ name ];copy = options[ name ];// Prevent never-ending loopif ( target === copy ) {continue;}// Recurse if we're merging plain objects or arraysif ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {if ( copyIsArray ) {copyIsArray = false;clone = src && jQuery.isArray(src) ? src : [];} else {clone = src && jQuery.isPlainObject(src) ? src : {};}// Never move original objects, clone themtarget[ name ] = jQuery.extend( deep, clone, copy );// Don't bring in undefined values} else if ( copy !== undefined ) {target[ name ] = copy;}}}}// Return the modified objectreturn target;};var item ={ 'a': 1, 'b': 2}Object.assign({}, item);
UPDATE: 05/31/2023a new global function was release that allows DEEP COPY called window.structuredClone()
While this isn't cloning, one simple way to get your result is to use the original object as the prototype of a new one.
You can do this using Object.create
:
var obj = {a: 25, b: 50, c: 75};var A = Object.create(obj);var B = Object.create(obj);A.a = 30;B.a = 40;alert(obj.a + " " + A.a + " " + B.a); // 25 30 40
This creates a new object in A
and B
that inherits from obj
. This means that you can add properties without affecting the original.
To support legacy implementations, you can create a (partial) shim that will work for this simple task.
if (!Object.create)Object.create = function(proto) {function F(){}F.prototype = proto;return new F;}
It doesn't emulate all the functionality of Object.create
, but it'll fit your needs here.
You could define a clone function.
I use this one :
function goclone(source) {if (Object.prototype.toString.call(source) === '[object Array]') {var clone = [];for (var i=0; i<source.length; i++) {clone[i] = goclone(source[i]);}return clone;} else if (typeof(source)=="object") {var clone = {};for (var prop in source) {if (source.hasOwnProperty(prop)) {clone[prop] = goclone(source[prop]);}}return clone;} else {return source;}}var B = goclone(A);
It doesn't copy the prototype, functions, and so on. But you should adapt it (and maybe simplify it) for you own need.
A
and B
reference the same object, so A.a
and B.a
reference the same property of the same object.
Edit
Here's a "copy" function that may do the job, it can do both shallow and deep clones. Note the caveats. It copies all enumerable properties of an object (not inherited properties), including those with falsey values (I don't understand why other approaches ignore them), it also doesn't copy non–existent properties of sparse arrays.
There is no general copy or clone function because there are many different ideas on what a copy or clone should do in every case. Most rule out host objects, or anything other than Objects or Arrays. This one also copies primitives. What should happen with functions?
So have a look at the following, it's a slightly different approach to others.
/* Only works for native objects, host objects are not** included. Copies Objects, Arrays, Functions and primitives.** Any other type of object (Number, String, etc.) will likely give ** unexpected results, e.g. copy(new Number(5)) ==> 0 since the value** is stored in a non-enumerable property.**** Expects that objects have a properly set *constructor* property.*/function copy(source, deep) {var o, prop, type;if (typeof source != 'object' || source === null) {// What do to with functions, throw an error?o = source;return o;}o = new source.constructor();for (prop in source) {if (source.hasOwnProperty(prop)) {type = typeof source[prop];if (deep && type == 'object' && source[prop] !== null) {o[prop] = copy(source[prop]);} else {o[prop] = source[prop];}}}return o;}