Accessing an array inside of JSON object from reviver - javascript

I have a JSON object formatted like {"Foo": ["B","A","R"]}
I am trying to access the values of the array like this:
var json = '{"Foo": ["B","A","R"]}';
expression = JSON.Parse(json, function(key, value){
if(key == "Foo"){
console.log(value.length); // logs "3"
console.log(value[1]); // logs "undefined"
}
});
If I ask for the length of value it returns the correct length of the array, but if I ask for the value it returns undefined and I am not quite sure why.There are other values in the JSON that I am able to access just fine, but they are not arrays. Any insight would be appreciated. Thanks!

You should use JSON.parse like this:
var json = '{"Foo":["B","A","R"]}';
var object = JSON.parse(json);
// object is now and object containing the data from 'json'
var expression = object["Foo"][1]; // object["Foo"] refers to the
// value with key "Foo"
(Calling JSON.parse with a callback parameter is an advanced feature for transforming the JSON object, not reading it. In almost all cases, though, you want to use it like the above code, with no callbacks.)

As mentioned in another answer, if you simply want to retrieve the second element of Foo, you can do that easily enough after parsing using standard property access techniques such as obj.Foo[1].
Assuming you really want to use the optional second "reviver" parameter to JSON.parse, you need to return the value from the "reviver" callback;
expression = JSON.Parse(json, function(key, value){
if (key == "Foo"){
console.log(value[1]);
}
return value;
^^^^^^^^^^^^^
});

The reason it appears you can't access value[1] but you can access value.length is (as mentioned by user663031) you don't have a return value.
The reviver function replaces one value with another, if no return is specified all functions will return undefined. The order the reviver receives the values is: first each of the values in the array separately, then the array.
In your code each value has already been replaced with "undefined", so the array has three undefined values as reported by the length. value[1] really is returning the value at position 1 but it is set to "undefined".

When the json string has arrays the reviver function is called with index, [Object] as key, value parameters .
This sniped of code that filter object properties on parse phase will be helpful:
var json = '{"_embedded": [{"a":"A","b":"B","links": {"c":"C"}},{"a":"A2", "b":"B2","links": {"c":"C2"}}]}';
var schemaNames=["_embedded", "a"];
var result= JSON.parse(json, function(k, v) {
console.log(k,v);
if ("" === k){
return v;
}
// On arrays k is a number
else if (schemaNames.indexOf(k) > -1 || !isNaN(k)){
return v;
}
});
console.log(JSON.stringify(result));
Output: {"_embedded":[{"a":"A"},{"a":"A2"}]}
https://jsfiddle.net/pdorgambide/vphbmtk1/

use this code
var json = {'foo' : ['B', 'A', 'R']};
$.each(json, function(key, value){if(key == 'foo'){console.log(value[1]);}});
you already have a json object so no need to parse it again.

Related

javaScript: Parsing a stringified object with JSON.parse removes references

I am trying to deep-clone an object, say "a" with k = JSON.parse(JSON.stringify(a)). It is important that I use the stringify way, since I am trying to save the object into a file and then load from it.
I stumbled upon a problem with references on the cloned object which is illustrated below:
var obj={};
obj.importantProperty={s:2};
obj.c=obj.importantProperty;
obj.d=obj.importantProperty;
console.log( obj.c === obj.d ); // Returns true
var cloned = JSON.parse(JSON.stringify(obj));
console.log( cloned.c === cloned.d ); // Returns false
I need the references to be kept when using JSON.parse, in the above example they are not. In my project the object is much more complicated, but in the end it comes down to the example above.
Thanks in advance to anyone who helps me with this :)
The proper way to do something like this would be to store the common referenced object(s) separately and reference it by an ID.
For instance, you can hold your importantProperty objects in an array and use the index as the ID:
var importantProperties = [
{ s: 1 },
{ s: 2 },
{ s: 3 }
];
var obj = {};
obj.importantProperty = importantProperties[1];
obj.c = obj.importantProperty;
obj.d = obj.importantProperty;
Then when you stringify the object you replace the referenced object with its index:
var stringified = JSON.stringify(obj, function(key, value) {
if (key) {
return importantProperties.indexOf(value);
}
return value;
});
console.log(stringified);
// prints {"importantProperty":1,"c":1,"d":1}
And then when you parse you simply reverse the process to revive the references:
var parsed = JSON.parse(stringified, function(key, value) {
if (key) {
return importantProperties[value];
}
return value;
});
console.log(parsed.c === parsed.d && parsed.d === parsed.importantProperty);
// prints true
Now, the example above works for your example code under the assumption that all properties in obj is an object from the importantProperties array. If that's not the case and it's only certain properties that is an importantProperties object, you need to check for that when replacing/reviving.
Assuming only the "importantProperty", "c" and "d" properties are such objects:
if (['importantProperty', 'c', 'd'].includes(key)) instead of just if (key)
If this isn't good enough and you don't want the property name to have anything to do with whether or not the value is an importantProperties object, you'll need to indicate this in the value together with the identifier. Here's an example of how this can be done:
// Replacing
JSON.stringify(obj, function(k, value) {
if (importantProperties.includes(value)) {
return 'ImportantProperty['
+ importantProperties.indexOf(value)
+ ']';
}
return value;
});
// Reviving
JSON.parse(stringified, function(k, value) {
if (/^ImportantProperty\[\d+\]$/.test(value)) {
var index = Number( value.match(/\d+/)[0] );
return importantProperties[index];
}
return value;
});
It is impossible to achieve your desired result using JSON because JSON format can contain only a limited ammount of data types (http://json.org/) and when you stringify an object to JSON some information gets lost.
Probably there is some other kind of serialization technique, but I would recommend you to look for another approach to store data.

change JSON.parse functionality

I tried to add default parameter for JSON.parse to convert time format to utc after using JSON.stringify
function json_deserialize_helper(key, value) {
if (key === "TimeStamp") {
value =new Date(value);
} return value; }
JSON.prototype.parse = function(j,f){ f= f ||
json_deserialize_helper; return JSON.parse(j,f); }
var obj = {"TimeStamp":"2016-06-09T10:37:52.000Z"} obj =
JSON.stringify(obj); console.log(obj); obj = JSON.parse(obj);
From the specs:
The JSON object is a single ordinary object that contains two functions, parse and stringify, that are used to parse and construct JSON texts.
This means that JSON is not a constructor function that would have its own prototype.
To do what you're trying to achieve, you'd have to overwrite JSON.parse:
JSON.parse = function () { /* your logic */ }
However, you are probably better off just creating a completely separate function that wraps JSON.parse instead of replacing JSON.parse itself. By replacing JSON.parse you risk breaking any libraries that use it.

Count number of object in another object , javascript-json

There seems to have many question asked similar on counting number of element already but I am failing to implement them with mine problem.
After jquery ajax I get JSON data returned which looks something like this
Object {0: Object, 1: Object , xxxx:"asdf" ,yyyy:"asdf", zzzz:"asdf"}
I want to get number of object between this { } braces ( not counting those xxx,yyy element )
I tried .length which doesn't work
I also tried using this Length of a JavaScript object but that return the number of element in each object. I just want the number of object
Thank You
Try this:
var json = { 0: {}, 1: {}, xxxx: "asdf", yyyy: "asdf", zzzz: "asdf" };
function typeOf( obj ) {
return ({}).toString.call( obj )
.match(/\s([a-zA-Z]+)/)[1].toLowerCase();
}
var total = 0;
for ( var o in json ) {
if ( typeOf( json[o] ) == 'object' ) {
total++;
}
}
console.log( total ); //=> 2
Everything is an object in JavaScript. The typeof operator is misleading and won't work in this case. You can use the typeOf function above that I extracted from this blog post: Fixing the JavaScript typeof operator (worth reading). There are other ways of doing it but this seems like the most straightforward.
If it's not just a coincidence that the objects are the ones with numeric property names, and the numeric properties count up sequentially, you could do something like this:
var obj = { /* your object here */ }
for (var i=0; i in obj; i++) {
// use obj[i] for something
}
// i is now equal to the number of numeric properties
This works because as soon as i is high enough that you've run out of properties the in operator will return false. Feel free to use .hasOwnProperty() instead if you prefer.
Obviously this is a specialised solution that doesn't test the type of the different properties at all. (To actually test the type see elclanrs' solution - and either way read the page he linked to.)
Say that the entire json is in a variable called json:
var total_objects = 0;
$.each(json, function () {
if (typeof this == 'object') {
total_objects++;
}
});
However, I am curious as to why you would need to know this.
You can use a customized version from the code of this question Length of Javascript Object (ie. Associative Array) and check for element's type using typeof operator and count only those which are an object (or an array).
Object.sizeObj = function(obj) {
var size = 0, key;
for (key in obj) {
if (typeof key[obj] === 'object' && obj.hasOwnProperty(key)) size++;
}
return size;
};
// Get the count of those elements which are an object
var objectsCount = Object.sizeObj(myArray);

Javascript distinguish a function in an object

Having an object like this:
var a = {
b: "string",
c: function(){
return "i return a string";
}
}
Doing
for (var key in a) {
console.log(typeof key);
};
Returns "string", "string" since b is a string and c returns a string.
Is there afunction that returns c -> function?
Returns "string", "string" since b is a string and c returns a string.
No. The reason it returns string, is that the attribute name b and the attribute name c are both strings; you're iterating over the keys of the object, not their values right now.
You could introduce attribute d, which was a function which returned a number or boolean, and you'd still get string.
Instead, enumerate over the values themselves;
for (var x in a) {
console.log(typeof a[x] );
};
If you want to see the type of the property instead of its key, should use the value together with the typeof operator.
for (var key in a) {
console.log(typeof a[key] );
};
Basically you will always get strings by iterating trough the keys of your object since they are represented as such.
But if you for example do console.log(typeof a[key]); Then you will get the expected output.
Change to:
for (var key in a) {
console.log(typeof a[key]);
};​
Live DEMO
console.log(typeof key); // gives you the key - "c"
console.log(typeof a[key]); // gives you the value of the "c" key - function.
Let me explain this little bit, so it's easy to understand to anyone. (its my first post here anyway.)
Try the following code, it says its a function.
console.log(typeof(a.c))
But what you have written is reading the property names. Try the following code to understand what's wrong with your code.
for (var key in a) {
console.log(key);
};
So basically what you are getting is correct. Because all property names are string.
Remember JSON objects have several restrictions, such as case sensitive, full path needed to traverse to properties etc..
Change your code as follows to get the typeof your properties,
Solution 1:
console.log(typeof(a[key]));
Solution 2:
console.log(typeof(eval('a.'+ key)));

Access Dictionary Object by String Index

I am trying to fill a Dictionary (JavaScript object) and retrieve values from it using a string index. For some reason, it always returns undefined when I try to retrieve the values.
My code goes something like this:
var _gauges = {};
//fill the gauges
_gauges[gaugeName] = gaugeObject;
And then I try to get access to it as follows:
setValue: function (gaugeName, newValue) {
var thisGauge = _gauges[gaugeName]; //always undefined
console.log(_gauges); //output shows all the elements that were added to _gauges
if (thisGauge) {
thisGauge.setCell(0, 1, newValue);
}
}
Am I doing anything wrong here?
Ok this was due to a typo... The param that was being passed into the setValue method does not match the one used to add the items to the dictionary object.

Categories