So, I was interested to find that JSON.stringify reduces a RegExp to an empty object-literal (fiddle):
JSON.stringify(/^[0-9]+$/) // "{}"
Is this behavior expected? I realize that a RegExp is an object with no properties to serialize. That said, dates are objects too; yet JSON.stringify() manages to produce a meaningful string:
JSON.stringify(new Date) // "2014-07-03T13:42:47.905Z"
I would have hoped that JSON would give RegExp the same consideration by using RegExp.prototype.toString().
If somebody would be interested, there is a nice workaround. I don't think, that current behaviour is correct. For example, Date instance is not serialized to empty object like RegExp, though it is an object and also has no JSON representation.
RegExp.prototype.toJSON = RegExp.prototype.toString;
// sample
var foo = { rgx: /qux$/ig, date: new Date }
JSON.stringify(foo);
//> {"rgx":"/qux$/gi","date":"2014-03-21T23:11:33.749Z"}"
Both JSON.stringify and JSON.parse can be customized to do custom serialization and deserialization by using the replacer and reviver arguments.
var o = {
foo: "bar",
re: /foo/gi
};
function replacer(key, value) {
if (value instanceof RegExp)
return ("__REGEXP " + value.toString());
else
return value;
}
function reviver(key, value) {
if (value.toString().indexOf("__REGEXP ") == 0) {
var m = value.split("__REGEXP ")[1].match(/\/(.*)\/(.*)?/);
return new RegExp(m[1], m[2] || "");
} else
return value;
}
console.log(JSON.parse(JSON.stringify(o, replacer, 2), reviver));
You just have to come up with your own serialization format.
Yes, because there's no canonical representation for a RegExp object in JSON. Thus, it's just an empty object.
edit — well it's 2018 now; the answers suggesting solutions using .toJSON() etc are probably fine, though I'd add the method to the prototype with
Object.defineProperty(RegExp.prototype, "toJSON", {
value: RegExp.prototype.toString
});
and so on. That ensures that the function name isn't enumerable, which makes the monkey-patch somewhat more hygienic.
Here's how I solved this issue:
Serialize it as a string:
var pattern = /foobar/i;
var serialized = JSON.stringify(pattern.toString());
Then rehydrate it using another regex:
var fragments = serialized.match(/\/(.*?)\/([a-z]*)?$/i);
var rehydrated = new RegExp(fragments[1], fragments[2] || '');
Preserves the pattern and flags - hope this helps someone!
RegExp.prototype.toJSON = RegExp.prototype.toString;
var regexp = /^[0-9]+$/;
var foo = { rgx: regexp.source, date: new Date };
var stringified = JSON.stringify(foo);
new RegExp(JSON.parse(stringified).rgx)
I think a good approach would be something like this:
function stringifyFilter(key,value) {
if (value instanceof RegExp) {
return value.toString();
}
return value;
}
var myObj = {
text : 'Howdy ho!',
pattern : /[a-z]+/i
}
JSON.stringify(myObj,stringifyFilter); // output: {"text":"Howdy ho!","pattern":"/[a-z]+/i"}
Related
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.
I know all about JSON.stringify or JSON.parse in the sense that one serializes an object and one deserializes the string back into an object. This is great!
However, I have the following situation:
var i = new MyMagicalObject();
var oi = JSON.parse(JSON.stringify(i));
console.log(i.numFields()); // this is fine
console.log(oi.numFields()); // this throws since Object has no method 'numFields'
Basically, I'd like to treat oi as an instance of "MyMagicalObject" since that's what it is.
I'm sure there's some magic about setting the prototype on oi or something, but I'm fairly new to JavaScript. Any help would be appreciated.
You can't "store" JavaScript functions in JSON strings.
The only data types that can be stored in JSON are:
Number
String
Boolean
Array
Object
null
(source)
Anything that isn't one of those types, gets ignored:
function Test(){
this.foo = function(){
return 'bar';
}
this.theAnswer = '42';
}
var t = new Test();
alert(t.foo());
alert(JSON.stringify(t))
Your problem could be easily solved by redesigning your MyMagicalObject class. Here is an example of JSON-friendly class:
function MyMagicalObject(props) {
this.props = props || {};
}
MyMagicalObject.prototype.get = function(key) {
return this.props[key];
};
MyMagicalObject.prototype.set = function(key, val) {
this.props[key] = val;
return this;
};
MyMagicalObject.prototype.toJSON = function() {
return this.props;
};
MyMagicalObject.prototype.numFields = function() {
return Object.keys(this.props).length;
};
This realization follows two rules:
It's constructor accepts JSON representation as a first argument.
It provides toJSON method to tell JS engine how to convert its instance to JSON.
Check the following example:
var obj = new MyMagicalObject();
obj.set('foo', 42).set('bar', 'baz');
alert(obj.numFields()); // 2
var str = JSON.stringify(obj);
var obj2 = new MyMagicalObject(JSON.parse(str));
alert(obj2.numFields()); // 2
You can create a new MyMagicalObject() and then overwrite its properties with the one from oi.
var t = new MyMagicalObject();
for(var k in oi) t[k]=oi[k];
That should do the trick. If you have a more complex object (with more than 1 dimension), search for a copy function that deep copies all properties.
Add oi.prototype = MyMagicalObject.prototype; after line 3.
or
create a new object and copy the properties:
var oi2 = new MyMagicalObject();
for (var p in oi) {
if (oi.hasOwnProperty(p)) {
oi2[p] = oi[p]
}
}
console.log(oi2.numFields());
Of course, JSON does not support Regex literals.
So,
JSON.stringify(/foo/)
gives:
{ }
Any workarounds?
I think this is the closest you can get:
RegExp.prototype.toJSON = function() { return this.source; };
JSON.stringify({ re: /foo/ }); // { "re": "foo" }
You can pass a a custom replacer function to JSON.stringify and convert the regular expression to a string (assuming that the expression is part of an array or object):
JSON.stringify(value, function(key, value) {
if (value instanceof RegExp) {
return value.toString();
}
return value;
});
If you don't actually want/need to create JSON, just call the toString() method of the expression.
Although JavaScript objects allow you to put regex as values, JSON does not as it is meant to store only data, not code.
As a workaround, you could convert your regular expression to a string using the toString() method.
var str = /([a-z]+)/.toString(); // "/([a-z]+)/"
You can use a replacer function:
JSON.stringify(/foo/,
function(k, v) {
if (v && v.exec == RegExp.prototype.exec) return '' + v;
else return v;
})
OK, first, i'm not going to seek a method to convert the Object to String.
but i'm facing a problem like this:
String.prototype.foo = function() {
return this;
};
var rawString = "abcde";
var fooString = "abcde".foo();
console.log(typeof(rawString) + ': ', rawString);
console.log(typeof(fooString) + ': ', fooString);
or jsfiddle you preferred.
also, a screenshot is attached:
as you can see, i did almost nothing in the prototype method foo, i just return this.
but the result of typeof are totally different
Why is this? how can i just return abcde rather thant {0: "a"...} ?
Thanks!
The this references the String Object, so you need to return it like
return this.toString();
which in turn, creates the primitive string version and returns it.
I have this on a javascript var: (it's a http returned data, and I don't know if it's an array or string - (how can we see that?) - Update: using typeof returned "string", so it's a string.
[{"nomeDominio":"gggg.fa"},{"nomeDominio":"rarar.fa"}]
How can we pass/transform that, into something like this:
["gggg.fa","rarar.fa"]
?
Thanks a lot,
MEM
You can figure out if is a string or an already parsed object by checking the type of your variable, e.g.:
ajax('url', function (response) {
alert(typeof response);
});
You will now figure out if it's a "string" or an Array "object".
If it's a string, you can use the JSON.parse method as #alcuadrado suggest, otherwise you can simply use the array.
Several answers suggest the use of the for-in statement to iterate over the array elements, I would discourage you to use it for that.
The for-in statement should be used to enumerate over object properties, to iterate over Arrays or Array-like objects, use a sequential loop as #Ken Redler suggests.
You should really avoid for-in for this purpose because:
The order of enumeration is not guaranteed, properties may not be visited in the numeric order.
Enumerates also inherited properties.
You can also use the Array.prototype.map method to meet your requirements:
var response = [{"nomeDominio":"gggg.fa"},{"nomeDominio":"rarar.fa"}];
var array = response.map(function (item) { return item.nomeDominio; });
// ["gggg.fa", "rarar.fa"]
This question is strongly related with this one.
I would suggest reading my answer there, as it would really help; and with a little variation, it would just work:
var responseString = '[{"nomeDominio":"gggg.fa"},{"nomeDominio":"rarar.fa"}]',
responseObject = JSON.parse(responseString),
nombresDeDominio = [];
for(var i in responseObject) {
nombresDeDominio.push(responseObject[i].nomeDominio)
}
Suerte!
Assuming your data always looks like that, you can do something like this:
var foo = [{"nomeDominio":"gggg.fa"},{"nomeDominio":"rarar.fa"}];
var newarr = [];
for ( var i=0,j=foo.length;i<j;i++ ) {
newarr.push( foo[i]['nomeDominio'] );
}
Here's a working fiddle.
function transform(array, f) {
var ret = [];
$.each(array, function(index) {
var v = f.call(this, index);
if(v) {
ret.push(v);
}
});
return ret;
}
var result = transform(
[{"nomeDominio":"gggg.fa"},{"nomeDominio":"rarar.fa"}],
function() { return this.nomeDominio; }
);
alert(result.toString());
it's a http returned data, and I don't
know if it's an array or string
It's JSON, and you can use it directly in JavaScript.
If you transform it into your array, you will lose the association key / value ; are you sure it's what you want ?
Okay, firstly to get the type of a "thing", use the "typeof" operator (note that the type of an array is an object, not 'array'!):
var a = "string";
var b = 1;
var c = new Array();
alert(typeof(a)); // string
alert(typeof(b)); // number
alert(typeof(c)); // object
To get at the values in the associative array (assuming it is one), you can just loop through it, like so:
var d = [{"nomeDominio":"gggg.fa"},{"nomeDominio":"rarar.fa"}];
d["bob"] = "alice";
d["gary"] = "stephen";
for(var key in d) {
alert(d[key]);
}