No, there is no build in way to deep clone objects.
And deep cloning is a difficult and edgey thing to deal with.
Lets assume that a method deepClone(a) should return a "deep clone" of b.
Now a "deep clone" is an object with the same [[Prototype]] and having all the own properties cloned over.
For each clone property that is cloned over, if that has own properties that can be cloned over then do so, recursively.
Of course were keeping the meta data attached to properties like [[Writable]] and [[Enumerable]] in-tact. And we will just return the thing if it's not an object.
Copyvar deepClone = function (obj) {
try {
var names = Object.getOwnPropertyNames(obj);
} catch (e) {
if (e.message.indexOf("not an object") > -1) {
// is not object
return obj;
}
}
var proto = Object.getPrototypeOf(obj);
var clone = Object.create(proto);
names.forEach(function (name) {
var pd = Object.getOwnPropertyDescriptor(obj, name);
if (pd.value) {
pd.value = deepClone(pd.value);
}
Object.defineProperty(clone, name, pd);
});
return clone;
};
This will fail for a lot of edge cases.
Live Example
As you can see you can't deep clone objects generally without breaking their special properties (like .length in array). To fix that you have to treat Array seperately, and then treat every special object seperately.
What do you expect to happen when you do deepClone(document.getElementById("foobar")) ?
As an aside, shallow clones are easy.
CopyObject.getOwnPropertyDescriptors = function (obj) {
var ret = {};
Object.getOwnPropertyNames(obj).forEach(function (name) {
ret[name] = Object.getOwnPropertyDescriptor(obj, name);
});
return ret;
};
var shallowClone = function (obj) {
return Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
);
};
Answer from Raynos on Stack OverflowNo, there is no build in way to deep clone objects.
And deep cloning is a difficult and edgey thing to deal with.
Lets assume that a method deepClone(a) should return a "deep clone" of b.
Now a "deep clone" is an object with the same [[Prototype]] and having all the own properties cloned over.
For each clone property that is cloned over, if that has own properties that can be cloned over then do so, recursively.
Of course were keeping the meta data attached to properties like [[Writable]] and [[Enumerable]] in-tact. And we will just return the thing if it's not an object.
Copyvar deepClone = function (obj) {
try {
var names = Object.getOwnPropertyNames(obj);
} catch (e) {
if (e.message.indexOf("not an object") > -1) {
// is not object
return obj;
}
}
var proto = Object.getPrototypeOf(obj);
var clone = Object.create(proto);
names.forEach(function (name) {
var pd = Object.getOwnPropertyDescriptor(obj, name);
if (pd.value) {
pd.value = deepClone(pd.value);
}
Object.defineProperty(clone, name, pd);
});
return clone;
};
This will fail for a lot of edge cases.
Live Example
As you can see you can't deep clone objects generally without breaking their special properties (like .length in array). To fix that you have to treat Array seperately, and then treat every special object seperately.
What do you expect to happen when you do deepClone(document.getElementById("foobar")) ?
As an aside, shallow clones are easy.
CopyObject.getOwnPropertyDescriptors = function (obj) {
var ret = {};
Object.getOwnPropertyNames(obj).forEach(function (name) {
ret[name] = Object.getOwnPropertyDescriptor(obj, name);
});
return ret;
};
var shallowClone = function (obj) {
return Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
);
};
The 2022 solution for this is to use structuredClone
See : https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
CopystructuredClone(x)
You should use the library json2.js. It is the basis for the standard JSON.stringify(...) that some browsers include natively.
You can find the page it originated from here: https://github.com/douglascrockford/JSON-js/blob/master/json2.js
The script automatically makes sure it only adds a JSON.stringify(...) method if it doesn't already exist so there is no danger including it in a browser that has it.
Depending on your use case, you can use a serialization library.
This is helpful when you want to store (or transfer) more complex Javascript objects without them breaking when you want to parse them back later (among other uses),
However, you won't get a standard JSON file but rather a superset of it that likely can only be used by the same library.
I've listed some of the reasons why you might want to consider a Serializer library instead of JSON.stringify() and JSON.parse(). Every Serializer is different but ideally, a Serializer can:
- Handle circular references, which JSON.parse() cannot handle.
- Handle all data types including Date, Error, undefined, or Functions - which JSON.stringify can't.
- Handle the conversion of non-standard data types.
- Deal with much larger objects.
- Handle Unicode or other special characters better.
Here's a library that I found easy to use: https://github.com/erossignon/serialijse
As an example use case for Serialization (although there are more prominent use cases and this is just how I used it), I used the minified version of the mentioned library to write a Developer Tools console code snippet to backup all the configurations and storage of a browser extension into a file to restore later. This would not have been possible with JSON.stringify() due to the custom types the extensions had stored in their local storage.
https://www.linkedin.com/posts/arunm-engineer_one-line-caused-the-entire-company-10x-down-activity-7178235801720303616-2f3p?utm_source=share&utm_medium=member_ios
If this is actually an issue, whats a better alternative? Will doing async await work?
You need to JSON.parse() your valid JSON string.
var str = '{"hello":"world"}';
try {
var obj = JSON.parse(str); // this is how you parse a string into JSON
document.body.innerHTML += obj.hello;
} catch (ex) {
console.error(ex);
}
JSON.parse is the opposite of JSON.stringify.
I really hate this function. it is just so easy to break and I need a better way to convert dictionaries fed from my python server, converted to strings by flask and recieved by JS to be converted into JSON so I can use the data
JSON.stringify turns a JavaScript object into JSON text and stores that JSON text in a string, eg:
var my_object = { key_1: "some text", key_2: true, key_3: 5 };
var object_as_string = JSON.stringify(my_object);
// "{"key_1":"some text","key_2":true,"key_3":5}"
typeof(object_as_string);
// "string"
JSON.parse turns a string of JSON text into a JavaScript object, eg:
var object_as_string_as_object = JSON.parse(object_as_string);
// {key_1: "some text", key_2: true, key_3: 5}
typeof(object_as_string_as_object);
// "object"
JSON.parse() is for "parsing" something that was received as JSON.
JSON.stringify() is to create a JSON string out of an object/array.
Take a closer look at the two comments you've put onto the question:
I suppose after re-reading my question, I'm seeing that in my C# example, I'm serializing the XML and THEN converting the serialized object ToString();. There inlies the rub.
and
I guess for continuity, it would be better (for me) to have a method that looks like this... JSON.serialize(obj).toString(); or jsonObject().toString();... this way it would look much like my C#... but now I'm over complicating it.
Now remember that in Javascript, an object is a hash (rather, if using Prototype or another framework, it should be qualified as a "special kind of hash" - but the simple form works for this example):
var obj = {
foo: 1,
bar: function() { console.log(this.foo); }
}
obj.foo; // 1
obj.bar; // function reference
obj.bar(); // function call
obj['foo']; // 1
obj['bar']; // function reference
obj['bar'](); // function call
The only reason a serialize() might be necessary in Javascript is to cut out the functions, references to other objects, etc.
So, to go back to your C# example - we've just cut out .Serialize() as unnecessary. An object is a hash, it's already serialized, further "serialization" would have to be done manually in your own code anyway. All that leaves you is .ToString().
Does .stringify() make more sense now?
This is because that JSON notation was specified in 1999 not after 2002 (asp.net is released at that year). so i guess they didn't know about the serialize.
Jokes apart,
Hearing the word serialization, first thing that comes to my mind is like converting the data to bytes, here JSON.stringify makes perfect sense as it converts the object to a string representation not a byte representation.
PS:
@Chase Florell, you can't just add JSON.serialize, as in strict mode, this code may actually fail in some browsers.
as JSON is not your average Object.
» npm install fast-json-stringify