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.
Related
Background: The module query-string is for example able to parse key=value&hello=universe to an object {key: 'value', hello: 'universe'}. However, the module author has decided that the returned object does not have a prototype. In other words, this "bastard" object is created by Object.create(null).
Problem: It would be convenient to use parsed.hasOwnProperty('hello') but that is not possible without the default object prototype. Of course, one could Object.prototype.hasOwnProperty.call(parsed, 'hello') but I think we can all agree that such an expression is kill-immediately-after-birth ugly.
Question: How to nicely convert the prototypeless object to have a default object prototype and methods such as hasOwnProperty? Additionally, can this be done without using the feared __proto__ or setPrototypeOf?
It would be convenient to use parsed.hasOwnProperty('hello') but that is not possible without the default object prototype
The whole point of creating such a "bastard object" is that you cannot do that - what if someone sent a query string ?hasOwnProperty=oops to your server?
How to nicely convert the prototypeless object to have a default object prototype and methods such as hasOwnProperty?
Don't. You should either use the long form with call, or just go for the in operator which does exactly what you need:
'hello' in parsed
In an ES6 environment, you might also want to convert the object to a proper Map and use it has method.
I wouldn't recommend changing the prototype of a third party package, it may be frozen and prone to runtime errors. I'd either use the built-in in operator as #Bergi suggested or the ES6 Reflect API.
const _ = console.info
const parsed = (
{ __proto__: null
, foo: 'fu'
, bar: 'bra'
}
)
_('foo' in parsed) // true
_('fu' in parsed) // false
/** ES6 (fully supported in current browsers) */
_(Reflect.has(parsed, 'foo')) // true
_(Reflect.has(parsed, 'fu')) // false
I can't say I've ever done this before, but here's one way to do it
let bastard = Object.create(null);
bastard.father = 'vader';
let adopted = Object.assign({}, bastard);
console.log(adopted.hasOwnProperty('father')); // => true
setPrototypeOf() is nothing to be feared of, yet without it you might do as follows;
var o1 = Object.create(null),
o2;
o1.test = "42";
o2 = Object.assign({},o1);
console.log(o2.test);
console.log(o2.constructor.prototype);
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\"]"
}
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.
After a lot of bug-hunting, I managed to narrow my problem down to this bit of code:
dup = {a: [1]}
chrome.storage.local.set({x: [dup, dup]});
chrome.storage.local.get(["x"], function(o) {console.log(JSON.stringify(o['x']));});
This prints out: [{"a":[1]},null]
Which I find to be a pretty strange behaviour. So my questions are:
Is this intentional? Is it documented?
Can you recommend a good solution to bypass this limitation?
My current idea is to use JSON.stringify (which handles this case correctly) and later parse the string. But that just seems wasteful.
Thanks.
No it is not intentional and should be reported as a bug: https://crbug.com/606955 (and now it is fixed as of Chrome 52!).
As I explained in the bug report, the cause of the bug is that the objects are identical. If your object dup only contains simple values (i.e. no nested arrays or objects, only primitive values such as strings, numbers, booleans, null, ...), then a shallow clone of the object is sufficient:
dup = {a: [1]}
dup2 = Object.assign({}, dup);
chrome.storage.local.set({x: [dup, dup2]});
If you need support for nested objects, then you have to make a deep clone. There are many existing libraries or code snippets for that, so I won't repeat it here. A simple way to prepare values for chrome.storage is by serializing it to JSON and then parsing it again (then all objects are unique).
dup = {a: [1]}
var valueToSave = JSON.parse(JSON.stringify([dup, dup]));
chrome.storage.local.set({x: valueToSave});
// Or:
var valueToSave = [ dup, JSON.parse(JSON.stringify(dup)) ];
chrome.storage.local.set({x: valueToSave});
I want to understand the basic differences clearly between Javascript object and JSON string.
Let's say I create the following JS variable:
var testObject = {one: 1,"two":2,"three":3};
Q1. Is the key/property name valid both with/without quotes? (e.g. "one" : 1)
If yes, what is the difference?
Q2: If I convert the above object using JSON.stringify(testObject), what’s the difference between the original JS object and the JSON?
I feel they are almost the same. Please elaborate on this.
Q3: For parsing a JSON string, is the method below recommended?
var javascriptObj = JSON.parse(jSonString);
Is the key/property name valid both with/without quotes ?
The only time you need to enclose a key in quotes when using Object Literal notation is where the key is a reserved word or contains a special character (if, :, - etc). It is worth noting that a key in JSON must be enclosed in double quotes.
If I convert the above object to JSON using var jSonString = JSON.stringify(testObject);, what is the difference between the 2 (JS obj and JSON)?
JSON is a data interchange format. It's a standard which describes how ordered lists and unordered maps, strings, booleans and numbers can be represented in a string. Just like XML and YAML is a way to pass structured information between languages, JSON is the same. A JavaScript object on the other hand is a physical type. Just like a PHP array, a C++ class/ struct, a JavaScript object is a type internal to JavaScript.
Here's a story. Let's imagine you've purchased some furniture from a store, and you want it delivered. However the only one left in stock is the display model, but you agree to buy it.
In the shop, the chest-of-drawers you've purchased is a living object:
var chestOfDrawers = {
color: "red",
numberOfDrawers: 4
}
However, you can't send a chest-of-drawers in the post, so you dismantle it (read, stringify it). It's now useless in terms of furniture. It is now JSON. Its in flat pack form.
{"color":"red","numberOfDrawers":4}
When you receive it, you then rebuild the chest-of-drawers (read, parse it). Its now back in object form.
The reason behind JSON, XML and YAML is to enable data to be transferred between programming languages in a format both participating languages can understand; you can't give PHP or C++ your JavaScript object directly; because each language represents an object differently under-the-hood. However, because we've stringified the object into JSON notation; i.e. a standardised way to represent data, we can transmit the JSON representation of the object to another language (C++, PHP), they can recreate the JavaScript object we had into their own object based on the JSON representation of the object.
It is important to note that JSON cannot represent functions or dates. If you attempt to stringify an object with a function member, the function will be omitted from the JSON representation. A date will be converted to a string;
JSON.stringify({
foo: new Date(),
blah: function () {
alert('hello');
}
}); // returns the string "{"foo":"2011-11-28T10:21:33.939Z"}"
For parsing a JSON string, is the method below recommended? var javascriptObj = JSON.parse(jSonString);
Yes, but older browsers don't support JSON natively (IE <8). To support these, you should include json2.js.
If you're using jQuery, you can call jQuery.parseJSON(), which will use JSON.parse() under the hood if it's supported and will otherwise fallback to a custom implementation to parse the input.
Q1: When defining object literals in javascript, the keys may include quotes or not. There is no difference except that quotes allow you to specify certain keys that would cause the interpreter to fail to parse if you tried them bare. For example, if you wanted a key that was just an exclamation point, you would need quotes:
a = { "!": 1234 } // Valid
a = { !: 1234 } // Syntax error
In most cases though, you can omit the quotes around keys on object literals.
Q2: JSON is literally a string representation. It is just a string. So, consider this:
var testObject = { hello: "world" }
var jSonString = JSON.stringify(testObject);
Since testObject is a real object, you can call properties on it and do anything else you can do with objects:
testObject.hello => "world"
On the other hand, jsonString is just a string:
jsonString.hello => undefined
Note one other difference: In JSON, all keys must be quoted. That contrasts with object literals, where the quotes can usually be omitted as per my explanation in Q1.
Q3. You can parse a JSON string by using JSON.parse, and this is generally the best way to do it (if the browser or a framework provides it). You can also just use eval since JSON is valid javascript code, but the former method is recommended for a number of reasons (eval has a lot of nasty problems associated with it).
Problems solved by JSON
Let's say you want to exchange regular JavaScript objects between two computers, and you set two rules:
The transmitted data must be a regular string.
Only attributes can be exchanged, methods are not transmitted.
Now you create two objects on the first host:
var obj1 = { one: 1,"two":2,"three":3 }; // your example
var obj2 = { one: obj1.one, two: 2, three: obj1.one + obj1.two };
How can you convert those objects into strings for transmission to the second host?
For the first object, you could send this string obtained form the literal definition '{ one: 1,"two":2,"three":3 }', but actually you can't read the literal in the script portion of the document (at least not easily). So obj1 and obj2 must actually be processed the same way.
You need to enumerate all attributes and their value, and build a string similar to the object literal.
JSON has been created as a solution to the needs just discussed: It is a set of rules to create a string equivalent to an object by listing all attributes and values (methods are ignored).
JSON normalizes the use of double-quotes for attribute names and values.
Remember that JSON is a set of rules only (a standard).
How many JSON objects are created?
Only one, it is automatically created by the JS engine.
Modern JavaScript engines found in browsers have a native object, also named JSON. This JSON object is able to:
Decode a string built using JSON standard, using JSON.parse(string). The result is a regular JS object with attributes and values found in the JSON string.
Encode attributes / values of a regular JS object using JSON.stringify(). The result is a string compliant with the JSON set of rules.
The (single) JSON object is similar to a codec, it's function is to encode and decode.
Note that:
JSON.parse() doesn't create a JSON object, it creates a regular JS object, there is no difference between an object created using an object literal and an object created by JSON.parse() from a JSON-compliant string.
There is only one JSON object, which is used for all conversions.
Going back to the questions:
Q1: The use of single of double quotes is allowed for object literals. Note that the quotes are used optionally for attributes names, and are mandatory for string values. The object literal itself is not surrounded by quotes.
Q2: Objects created from literals and using JSON.parse() are strictly the same. These two objects are equivalent after creation:
var obj1 = { one: 1, "two": 2, "three": 3 };
var obj2 = JSON.parse('{ "one": "1", "two": "2", "three": "3" }');
Q3: On modern browsers JSON.parse() is used to create a JS object from a JSON-compliant string. (jQuery has also an equivalent method that can be used for all browsers).
Q1 - in JS you only need to use quotes if the key is a reserved word or if it would otherwise be an illegal token. In JSON you MUST always use double quotes on key names.
Q2 - the jsonString is a serialised version of the input object ...
Q3 - which may be deserialised to an identical looking object using JSON.parse()
Question already has good answers posted, I am adding a small example below, which will make it more easy to understand the explanations given in previous answers.
Copy paste below snippet to your IDE for better understanding and comment the
line containing invalid_javascript_object_no_quotes object declaration to avoid compile time error.
// Valid JSON strings(Observe quotes)
valid_json = '{"key":"value"}'
valid_json_2 = '{"key 1":"value 1"}' // Observe the space(special character) in key - still valid
//Valid Javascript object
valid_javascript_object_no_quotes = {
key: "value" //No special character in key, hence it is valid without quotes for key
}
//Valid Javascript object
valid_javascript_object_quotes = {
key:"value", //No special character in key, hence it is valid without quotes for key
"key 1": "value 1" // Space (special character) present in key, therefore key must be contained in double quotes - Valid
}
console.log(typeof valid_json) // string
console.log(typeof valid_javascript_object_no_quotes) // object
console.log(typeof valid_javascript_object_quotes) // object
//Invalid Javascript object
invalid_javascript_object_no_quotes = {
key 1: "value"//Space (special character) present in key, since key is not enclosed with double quotes "Invalid Javascript Object"
}