I have a JS object
{
aString:[aNumber, aURL]
}
JSON.stringify() returns
{
"aString":"[number, \"aURL\"]"
}
I thought that valid JSON can have arrays as values. Can I have stringify return the JSON string without converting the array into a string? Basically I need turn the whole JS object straight into a string, without any modification.
Is there a better way to do this? I've been looking around but everyone suggests using JSON.stringify if I want an object to string, and no one has raised this problem.
EDIT: Thanks for the quick responses. Here is how I created my JS object, please let me know if I messed up and how!
cookie = {};
// productURL is a string, timer is a number, imageSrc is a URL string
cookie[productURL] = [timer, imageSrc];
// then, I just stringified cookie
newCookie = JSON.stringify(cookie);
If it is also relevant, I am setting an actual cookie's value as the resulting JSON string, in order to access it in another set of functions. Setting the cookie's value does do some URI encoding of its own, but I've actually been grabbing the value of newCookie in the Chrome console as well and it also returns the Array as a string.
If an object you're trying to stringify has a toJSON function, that will be called by JSON.stringify. Most likely you have an external library that's adding Array.prototype.toJSON.
For example, an old version (1.6) of Prototype JS will "conveniently" add that for you.
Prototype 1.6.1:
alert(JSON.stringify([1, 2, 3]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.6.1/prototype.min.js"></script>
Whereas a newer version will not.
Prototype 1.7.2:
alert(JSON.stringify([1, 2, 3]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.min.js"></script>
You could try deleting Array.prototype.toJSON just to see if that's what's causing the problem. If it is, you might want to look into upgrading/deprecating any libraries in your code that do weird things like that.
Prototype 1.6.1 (after deleting toJSON)
delete Array.prototype.toJSON;
alert(JSON.stringify([1, 2, 3]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.6.1/prototype.min.js"></script>
Based on your description this is not what should happen.
If you have code like this:
var obj = {
aString:[123, "test"]
}
document.getElementById("out").value = JSON.stringify(obj);
it will generate the expected json:
{"aString":[123,"test"]}
also see https://jsfiddle.net/zudrrc13/
in order to produce your output the original object would have to look something like:
var obj = {
aString:"[123, \"test\"]"
}
Related
I am currently trying to debug the issue in the title.
Here's some additional information:
I am receiving the list from a DynamoDB set.
JSON.stringify(list) prints: ["elt1","elt2"]
Array.isArray(list) === false
list.map is undefined, list.forEach is undefined
const list2 = JSON.parse(JSON.stringify(list))
Array.isArray(list2) === true
I have tried the above hack, and it does solve the issue- but it is definitely not conventional.
You've made an erroneous assumption: just because something produces an Array when run through JSON.stringify() does not necessarily mean it in itself is an Array to start. Consider this example:
class MyClass {
toJSON() {
return ['a', 'b'];
}
}
const list = new MyClass();
console.log(JSON.stringify(list));
console.log(Array.isArray(list));
console.log(list.map);
console.log(list.forEach);
In other words - it's entirely possible for a class to override the toJSON() method and fundamentally alter how it is processed by JSON.stringify(). I would suspect what you're encountering is that list is not really an Array (as you allude) but rather some other type that behaves this way when being stringified.
It's return valid output (list.map is undefined, list.forEach is undefined),t because JSON.stringify() convert into a string and you can't apply any array function on in it.
This question already has answers here:
JavaScript: How to pass object by value?
(14 answers)
Closed 5 years ago.
This is my first function, i pass to json
end if it is the first time i save the json is original.
function loadchart2(div, json, lista,tipo) {
var listaId = lista;
if(l==0){
jsonSecCall =JSON.parse(JSON.stringify(json));
listaSecCall=listaId;
l++;
}
I modify json ,and click a button.
Call second function and call loadcart2 and pass the json original but actually receives the json modify, What???
$("#giorni").on('click',function () {
var nuova=jsonSecCall;
$("#svgDateLine2").remove();
loadchart2("content", nuova,listaSecCall,"giorni");
checkContainer();
});
Probably the json it is gone for reference, is possible??
This is an example https://jsfiddle.net/tsjvmsd0/.
First console log print json modified, is ok, the next console log they should
print the original json, but print json modified.
This is the con of javascript. Everything in JS is passed by value, except objects, due to they are collections of references. That was done in performance reasons - it is costly to make copy of whole object.
To modify object without mutating the original, you should copy it. One way is to use Object.assign. It's probably better than making so deep copy of object ;-)
Then the snippet will be
var copy = {}
Object.assign(copy, source)
I dont know the types of your variables but normally I use Array.prototype.slice for copying.
var a = [1, 2, 3];
var b = a.slice(0); //Creates a new array
For copying objects see #alexcleac answer.
Firstly, it doesn't look like you are dealing with JSON, it looks like you are dealing with an object (or an array). JSON is a string.
Secondly, you aren't passing in the original JSON to loadchart2 (as you have figured out). You already modified the object reference by the variable jsonSecCall
What you probably want to do is actually maintain the original JSON (string) form of the object and use that as your original, unmodified object. You can do a JSON.parse on it whenever you want an object reference of your original.
This works fine:
$cookies.animals = []
$cookies.animals.push({cat: 'meow'})
console.log($cookies.animals) -> [Object]
But identical code inside a factory function doesn't work:
addAnimal: function(id, name, price){
console.log($cookies.animals) //-> [object Object]
$cookies.animals.push({cat: 'meow'}) //-> TypeError: undefined is not a function
}
So why am I getting a TypeError?
If I do this
addAnimal: function(id, name, price){
$cookies.animals = []
console.log($cookies.animals) //-> []
$cookies.animals.push({cat: 'meow'}) //-> works
}
It works (though of course it resets the array) so some something weird is happening to $cookies.animals.
If we look at my console.log inside the factory function:
We get this:
[object Object]
Object with a capital O is my cat, but that weird object is doing something evil I think. Where does it even come from?
Really don't know what's going on to be quite honest. Help please. All I'm trying to do is append to an array...
Per the AngularJS $cookie documentation:
Only a simple Object is exposed and by adding or removing properties to/from this object, new cookies are created/deleted at the end of current $eval. The object's properties can only be strings.
Your initial code works because you can, at any time, set any type of property on any object. Angular does not hold onto your non-string values, though, so your animals property is no longer set in the latter use context. You'll have to serialize and deserialize (probably via JSON) when writing and reading (respectively).
So you'll need to do something like this to initialize the cookie:
var animals = [];
animals.push('Furry Cat');
$cookies.animals = JSON.stringify(animals);
Later when reading, you'd need to do this:
var animal_cookie_value = $cookies.animals,
animals = animal_cookie_value ? JSON.parse(animal_cookie_value) : [];
As for your added remark of:
Object with a capital O is my cat, but that weird object is doing something evil I think. Where does it even come from?
When you see
object Object
in JavaScript you are seeing the output of the default toString() method on JavaScript objects. In other words, you used an object in context of a string, so JS cast it to string (which results in the value you're questioning).
FWIW, I develop a JavaScript cookie library which allows you to pass in any data and it handles the serialization for you. It is currently hosted on Google code, but I am working on moving it to GitHub and hope to add an AngularJS module for it someday.
I'm experiencing an odd behavior (maybe it isn't odd at all but just me not understanding why) with an javascript array containing some objects.
Since I'm no javascript pro, there might very well be clear explanation as to why this is happening, I just don't know it.
I have javascript that is running in a document. It makes an array of objects similar to this:
var myArray = [{"Id":"guid1","Name":"name1"},{"Id":"guid2","Name":"name2"},...];
If I print out this array at the place it was created like JSON.stringify(myArray), I get what I was expecting:
[{"Id":"guid1","Name":"name1"},{"Id":"guid2","Name":"name2"},...]
However, if I try to access this array from a child document to this document (a document in a window opened by the first document) the array isn't an array any more.
So doing JSON.stringify(parent.opener.myArray) in the child document will result in the following:
{"0":{"Id":"guid1","Name":"name1"},"1":{"Id":"guid2","Name":"name2"},...}
And this was not what I was expecting - I was expecting to get the same as I did in teh parent document.
Can anyone explain to me why this is happening and how to fix it so that the array is still an array when addressed from a child window/document?
PS. the objects aren't added to the array as stated above, they are added like this:
function objTemp()
{
this.Id = '';
this.Name = '';
};
var myArray = [];
var obj = new ObjTemp();
obj.Id = 'guid1';
obj.Name = 'name1';
myArray[myArray.length] = obj;
If that makes any difference.
Any help would be much appreciated, both for fixing my problem but also for better understanding what is going on :)
The very last line might be causing the problem, have you tried replacing myArray[myArray.length] = obj; with myArray.push(obj);? Could be that, since you're creating a new index explicitly, the Array is turned into an object... though I'm just guessing here. Could you add the code used by the child document that retrieves myArray ?
Edit
Ignore the above, since it won't make any difference. Though, without wanting to boast, I was thinking along the right lines. My idea was that, by only using proprietary array methods, the interpreter would see that as clues as to the type of myArray. The thing is: myArray is an array, as far as the parent document is concerned, but since you're passing the Array from one document to another, here's what happens:
An array is an object, complete with it's own prototype and methods. By passing it to another document, you're passing the entire Array object (value and prototype) as one object to the child document. In passing the variable between documents, you're effectively creating a copy of the variable (the only time JavaScript copies the values of a var). Since an array is an object, all of its properties (and prototype methods/properties) are copied to a 'nameless' instance of the Object object. Something along the lines of var copy = new Object(toCopy.constructor(toCopy.valueOf())); is happening... the easiest way around this, IMO, is to stringency the array withing the parent context, because there, the interpreter knows it's an array:
//parent document
function getTheArray(){ return JSON.stringify(myArray);}
//child document:
myArray = JSON.parse(parent.getTheArray());
In this example, the var is stringified in the context that still treats myArray as a true JavaScript array, so the resulting string will be what you'd expect. In passing the JSON encoded string from one document to another, it will remain unchanged and therefore the JSON.parse() will give you an exact copy of the myArray variable.
Note that this is just another wild stab in the dark, but I have given it a bit more thought, now. If I'm wrong about this, feel free to correct me... I'm always happy to learn. If this turns out to be true, let me know, too, as this will undoubtedly prove a pitfall for me sooner or later
Check out the end of this article http://www.karmagination.com/blog/2009/07/29/javascript-kung-fu-object-array-and-literals/ for an example of this behavior and explanation.
Basically it comes down to Array being a native type and each frame having its own set of natives and variables.
From the article:
// in parent window
var a = [];
var b = {};
//inside the iframe
console.log(parent.window.a); // returns array
console.log(parent.window.b); // returns object
alert(parent.window.a instanceof Array); // false
alert(parent.window.b instanceof Object); // false
alert(parent.window.a.constructor === Array); // false
alert(parent.window.b.constructor === Object); // false
Your call to JSON.stringify actually executes the following check (from the json.js source), which seems to be failing to specify it as an Array:
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
//stringify
I wanted to converted the javascript object into string so that it should work in all the browsers
I used object.toSource(); to convert it to string. It work's fine only in firefox.
In IE it shows
Object doesn't support this property or method
I replaced it with JSON.stringify(object); this time i get an error as "Circular reference in value argument not supported". I'm not sure what the problem is.
I got this output when I use object.toSource();
The jJSON data is
({test:["456", "Test event", (new Date(1332131400000)), (new
Date(1332135000000)), "0", 0, 0, "16", 1, "Some place",
"...............
I need to convert this JSON data into string.......
Can any one help me on this?
Thanks
The toSource() method is not supported in IE; JavaScript implementations of browsers are known to be somewhat different, this is one of those cases.
JSON can't represent circular references. This is an example of a circular reference:
var a = {}, b = {a: a};
a.b = b;
// Now I can go a.b.a.b.a.b.a.b... forever; there's no way to represent this in JSON
You should probably implement your own serialization method, possibly by overriding toString(). If you want to stick with JSON, you'll have to remove the circular reference.
Circular reference means just that; there is a circular reference in your object. For instance, imagine the js code:
var a = {a: 'test'};
a.b = a;
Now we want to stringify a.
We start with {"a":"test","b":, then we see that a.b is an object, ok, we call stringify on that too and end up with {"a":"test","b":{"a":"test","b": and so forth. As you can probably see, this cycle will never end, thus you have a circular reference which can't be serialized in this manner.
May be you will interested in JSONplus.It can solve "Circular reference".But its document is chinese.