I've added a field "max" to the JS array prototype. I'm having trouble seeing this addition when I stringify the array. I've tried to overwrite the toJSON function but to no avail.
Array.prototype.max = 0;
Array.prototype.toJSON = function(){
var o = this;
o.max = this.max;
return o;
};
var a = [1,2,3];
a.max = 10;
console.log(JSON.stringify(a));
//'[1,2,3]'
I'd like to avoid doing something like {array_field:a,max_field:max} and just use the array object - is this possible? What am I doing wrong?
You have a few options here, none of them will do exactly what you want.
Since JSON arrays are strictly limited to integer keys[1], you can't send down the value of max directly.
Your choices include:
Using an object instead of an array. You loose all of the array magic, but it might work better for you.
Send down meta-data outside your array, such as a configuration object that includes both max and your array values
Force the array to be max long before sending it down. JSON will encode unused array elements with null.
Use a custom serialzer/deserializer. You could even code things in JSONS + the extras. In reality, this pretty much turns out the same as the second option.
[1] Unlike JavaScript Objects
Related
I am fetching data from db and storing it in an array in key value pair, so that i can get values of respective keys as below
var test = [];
for () //fetching and storing from db
{
test[key_array[i]] = "value i";
.
.
.
}
test["id_1"] = "value 1"; //to get the value of id_<number>
we can achive this though objects too. I wanted to know which is the better option to consider, if we want a fast and optimized code
Is array better than objects for storing and searching key value pairs in javascript?
No. In fact, you're not using the array as an array, you're using it as an object. You could literally change your
var test = [];
to
var test = {};
// or
var test = Object.create(null); // To avoid it having a prototype
and it would do the same thing you're seeing now:
var test = {};
test["id_1"] = "value_1";
console.log(test["id_1"]);
var test2 = Object.create(null);
test2["id_2"] = "value_2";
console.log(test2["id_2"]);
(And you should change it, since using an array only for its object features is confusing to people maintaining your code.)
[] is a property accessor that accepts the property name as a string. (We use it with standard arrays as well, using numbers, but in theory they get converted to strings before the property is looked up, because standard arrays aren't really arrays at all¹.)
In ES2015+, of course, you'd probably use a Map, not an object:
const test = new Map();
test.set("id_1", "value_1");
console.log(test.get("id_1"));
¹ That's a post on my anemic little blog.
Arrays, are just a kind of object specialized for storing sequences of things. If you evaluate typeof [], it produces "object".
https://eloquentjavascript.net/04_data.html#h_cqg63Sxe3o
The idea of an array is store sequences of data with the same type or logic structure. Thus, is logic put the data come from a db into an array.
Note that you should avoid this because it can become very confusing :
var test = [];
test["id_1"] = "value_1";
test[-1] = "value_0";
console.log(test[-1],test["id_1"]);
console.log(test.length,Array.isArray(test));
It lets you think that test is an array (and it is) but test[-1] and test["id_1"] are not part of the array (that's why Array.isArray(test) returns true, but test.length is still equal to 0. See explanation on link provided by mister T.J. Crowder
I am a bit confused at this point on what is an object, what is an array, and what is a JSON. Can someone explain the differences in syntax between the two? and how to add items to each, how to merge each type, and such? I am trying to get this function to take the new information from a JSON object (I think) and merge it with some new information. This information will then be passed to a PHP script to be processed.
Here is the console output:
{"public":{"0":["el29t7","3bmGDy"]}}
{"public":"[object Object][object Object]"}
Here is the JS I am using:
/* Helper function to clean up any current data we have stored */
function insertSerializedData(ids, type) {
// Get anything in the current field
current_data = $('#changes').val();
if (!current_data) {
var data = {};
data[index++] = ids;
var final_data = {};
final_data[type] = data;
$('#changes').val(JSON.stringify(final_data));
} else {
current_data = JSON.parse(current_data);
var data = {};
data[index++] = ids;
// Does the index exist?
if (type in current_data) {
var temp_data = current_data[type];
current_data[type] = temp_data + data;
} else {
current_data[type] = data;
}
//var extra_data = {};
//extra_data[type] = data;
//$.merge(current_data, extra_data);
$('#changes').val(JSON.stringify(current_data));
}
console.log($('#changes').val());
}
The idea is if the key (public, or whatever other ones) doesn't exist yet, then to make it point to an array of arrays. If it does exist though, then that of array of arrays need to be merged with a new array. For instance:
If I have
{"public":{"0":["el29t7","3bmGDy"]}}
and I want to merge it with
["aj19vA", "jO71Ba"]
then final result would be:
{"public":{"0":["el29t7","3bmGDy"], "1":["aj19vA", "jO71Ba"]}}
How can i go about doing this? Thanks
Excellent two-part question. Overall, the second question is non-trivial because of the complexity of the first.
Question 1:
what is an object, what is an array, and what is a JSON. Can someone
explain the differences in syntax between the two?
Question 2:
and how to add items to each,
Question 3:
how to merge each type, and such?
Answer 1:
This is a common stumbling point because, JavaScript is more flexible than one might initially expect. Here is the curve.
In JavaScript everything is an object.
So here is the code for each:
//What is an object?
var obj = { };
var obj2 = { member:"value", myFunction:function(){} }
Above is an empty object. Then another object with a variable and a function.
They are called object-literals.
//What is an array
var array1 = [ ] ;
var array2 = [0,1,2,3,4];
Above is an empty array. Then another array with five Integers.
Here is the curve that causes confusion.
//Get elements from each of the prior examples.
var x = obj2["member"];
var y = array2[1];
What??? Both Object and Array are accessing values with a bracket?
This is because both are objects. This turns out to be a nice flexibility for writing advanced code. Arrays are objects.
//What is JSON?
JSON stands for JavaScript Object Notiation. As you might have guessed. Everything is an object... It is also an { }; But it is different because - it is used to transfer data to - and - from JavaScript, not actually used (commonly) in JavaScript. It is a file transfer format.
var JSONObject = {"member":"value"};
The only difference to the prior example is quotes. Essentially we are wrapping the object literal as a string so that it can be transferred to a server, or back, and it can be reinterpreted, very easily. Better than XML - because it does not have to be custom-parsed. Just call, stringify() or ParseJSON(). Google it. The point is... JSON can be converted into an object-literal JS object, and JS object-literals can be converted into JSON, for transfer to a server or a CouchDB database, for example.
Sorry for the tangent.
Answer 2:
How to add an item to each? Here is where the curve stops being a nuisance, and starts being awesome! Because everything is an object, it is all just about the same.
//Add to an object
var obj {member1:"stringvalue"}
obj.member2 = "addme"; //That is it!
//Add to an array
var array1 [1,2,3,4,5];
array1[0] = "addme";
array[6] = null;
//We shouldn't mix strings, integers, and nulls in arrays, but this isn't a best-practice tutorial.
Remember the JS object syntax and you may start to see a whole new flexible world of objects open up. But it may take a bit.
Answer 3: Ah, yeah... how to merge.
There are seriously (very many) ways to merge two arrays. It depends on exactly what you need. Sorted, Duplicated, Concatenated... there are a few.
Here is the answer!
UPDATE: How to make a beautiful multiple dimensional array.
//Multiple Dimension Array
var array1 = [1,2,3];
var array2 = [3,4];
var arraysinArray = [array1,array2]; //That is it!
Here is the curve again, this could be in an object:
var obj{
array1:[1,2,3],
array2:[3,4]
}
JavaScript is powerful stuff, stick with it; it gets good. : )
Hope that helps,
All the best!
Nash
In this case, think of a JavaScript's object literal {} as being like PHP's associative array.
Given that, an "array of arrays" actually looks like this (using your above desired output):
{public: [["el29t7","3bmGDy"], ["aj19vA", "jO71Ba"]]}
So here we have an object literal with a single property named "public" whose value is a 2-dimensional array.
If we assign the above to a variable we can then push another array onto "public" like this:
var current_data = {public: [["el29t7","3bmGDy"], ["aj19vA", "jO71Ba"]]};
// Using direct property access
current_data.public.push(["t9t9t9", "r4r4r4"]);
// Or using bracket notation
current_data["public"].push(["w2w2w2", "e0e0e0"]);
current_data's value is now:
{public: [
["el29t7","3bmGDy"],
["aj19vA", "jO71Ba"],
["t9t9t9", "r4r4r4"],
["w2w2w2", "e0e0e0"]
]}
So now "public" is an array whose length is 4.
current_data.public[0]; // ["el29t7","3bmGDy"]
current_data.public[1]; // ["aj19vA", "jO71Ba"]
current_data.public[2]; // ["t9t9t9", "r4r4r4"]
current_data.public[3]; // ["w2w2w2", "e0e0e0"]
MDN has very good documentation on Array for insight on other functions you might need.
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array
First is an object, that contains array, second is an array.
DEMO showing display output http://jsfiddle.net/GjQCV/
var object={"public":{"0":["el29t7","3bmGDy"]}};
var arr=["aj19vA", "jO71Ba"] ;
/* use object notation to add new property and value which is the array*/
object.public[1]=arr;
It'd be much more natural if {"0": ...} were a true array rather than an object, but anyway:
function maxKey(b) {
var max;
for( var key in b )
var max = key;
return max;
}
function merge(a,b) {
for( var key in a ) {
b[key] = b[key] ? (b[key][maxKey(b)+1]=a[key], b[key]) : a[key];
}
return b;
}
Note that this assumes you would insert at the next integer index
Arrays are a particular kind of Javascript object
JSON is a way of representing Javascript objects (and as such can represent arrays and more)
Objects are much more general, and can be simple objects that can be represented as JSON, or can contain functions and prototypes.
So, this is not an array of arrays (you would access items using JSON notation like myobj["0"]):
{"0":["el29t7","3bmGDy"], "1":["aj19vA", "jO71Ba"]}
This is an array of arrays, which means you can use the push method to add an item, and access items using array notation like myobj[0]:
[ ["el29t7","3bmGDy"], ["aj19vA", "jO71Ba"] ]
It seems like the structure you want is something like this:
var myobj = { "public": [ ["key", "value"], ["key", "value"] ] }
Then if you want to add/merge new items, you'd write this:
if (myobj["public"] != null) {
myobj["public"].push(["newkey", "newval"]);
} else {
myobj["public"] = ["newkey", "newval"];
}
I was trying to define an array (including other arrays as values) in a single javascript statement, that I can loop through to validate a form on submission.
The function I wrote to (try to) create inline arrays follows:
function arr(){
var inc;
var tempa = new Array(Math.round(arguments.length/2));
for(inc=0; inc<arguments.length; inc=inc+2) {
tempa[arguments[inc]]=arguments[inc+1];
}
return tempa;
}
This is called three times here to assign an array:
window.validArr = arr(
'f-county',arr('maxlen',10, 'minlen',1),
'f-postcode',arr('maxlen',8, 'minlen',6)
);
However in the javascript debugger the variable is empty, and the arr() function is not returning anything. Does anyone know why my expectations on what this code should do are incorrect?
(I have worked out how to create the array without this function, but I'm curious why this code doesn't work (I thought I understood javascript better than this).)
Well from what your code does, you're not really making arrays. In JavaScript, the thing that makes arrays special is the management of the numerically indexed properties. Otherwise they're just objects, so they can have other properties too, but if you're not using arrays as arrays you might as well just use objects:
function arr(){
var inc;
var tempa = {};
for(inc=0; inc<arguments.length; inc=inc+2) {
tempa[arguments[inc]]=arguments[inc+1];
}
return tempa;
}
What you're seeing from the debugger is the result of it attempting to show you your array as a real array should be shown: that is, its numerically indexed properties. If you call your "arr()" function as is and then look at (from your example) the "f-county" property of the result, you'll see something there.
Also, if you do find yourself wanting a real array, there's absolutely no point in initializing them to a particular size. Just create a new array with []:
var tempa = [];
Your code works. Just inspect your variable, and you will see that the array has the custom keys on it. If not expanded, your debugger shows you just the (numerical) indixed values in short syntax - none for you.
But, you may need to understand the difference between Arrays and Objects. An Object is just key-value-pairs (you could call it a "map"), and its prototype. An Array is a special type of object. It has special prototype methods, a length functionality and a different approach: to store index-value-pairs (even though indexes are still keys). So, you shouldn't use an Array as an associative array.
Therefore, their literal syntax differs:
var array = ["indexed with key 0", "indexed with key 1", ...];
var object = {"custom":"keyed as 'custom'", "another":"string", ...};
// but you still can add keys to array objects:
array.custom = "keyed as 'custom'";
I know this isn't the best way to do it, but I have no other choice :(
I have to access the items in JSONObject by their index. The standard way to access objects is to just wirte this[objectName] or this.objectName. I also found a method to get all the fields inside a json object:
(for (var key in p) {
if (p.hasOwnProperty(key)) {
alert(key + " -> " + p[key]);
}
}
(Soruce : Loop through Json object).
However there is no way of accessing the JSONfields directly by a index. The only way I see right now, is to create an array, with the function above, get the fieldname by index and then get the value by fieldname.
As far as I see it, the p (in our case the JSON file must be an iteratable array to, or else the foreach loop wouldn't work. How can I access this array directly? Or is it some kind of unsorted list?
A JSON Object is more like a key-value-map; so, yes, it is unsorted. The only way to get around is the index->property name map you've already mentioned:
var keysbyindex = Object.keys(object);
for (var i=0; i<keysbyindex.length; i++)
alert(object[keysbyindex[i]]);
But why would you need these indexes? A unsorted map also has no length property, as an Array had. Why don't you use the for-in-loop
var counter = 0; // if you need it
for (var key in object) {
alert(object[key])
counter++;
}
? If you have a parsed JSON object, i.e. a plain JS Object, you won't have to worry about enumerable prototype properties.
Based on Bergis anserwer this is my solution:
var keysbyindex = Object.keys(this);
alert(this[keysbyindex[index]]);
return this[keysbyindex[index] || ""];
However, I think (not tested) it's extremly bad regaring performace and shouldn't be used! But desperate times require desperate measures.....
I don't think you can actually achieve this without creating your own parsing of JSON. You're writing that you want to go trough a JSON-object, but what you're actually trying to do is go trough a plain old Javascript object. Json is simply a string-representation used to transfer/store said object, and in here lies the main problem: the parser that transforms the string into an actual object (ie. the browser in most cases) can chose to ignore the order it finds the properties if it want to. Also, different browsers might have different approaches to parsing JSON for all you know. If they simply use a hash-map for the object that it's simple to loop through it, but the order won't be dependent on the order of the keys in the file, but rather the keys themselves.
For example, if you have the json {"b":"b","a":"a"} and do the for in loop, under some implementations you might end up with a comming first, and in others you might end up with b.
var jsn = {keyName: 'key value result come here...'};
var arr = jsn ? $.map(jsn, function (el) { return el }) : [0];
console.log(arr[0])
$('.result').text(arr[0]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="result"></span>
In PHP, if you do this
$var = array();
$var[5000] = 1;
echo count($var);
It prints 1.
In JS it makes the "missing" elements.
<script type="text/javascript">
var fred = [];
fred[10] = 1;
alert(fred.length);
</script>
Alerts "11".
Can I prevent this? Is it good for anything? I'm a PHP coder trying to adapt to Javascript.
EDIT:
I'm working on an app that uses Google Maps v2 and markerManager. The code has been working for ages, but a problem has suddenly arisen in Chrome (17.0.963.56 m) where markers seem to be duplicated (or more) and then rendering moved markers goes completely wrong, often followed by a browser freeze-up. Looking in the DOM using Firebug, I found gazillions of "undefined" elements in arrays under the grid_ variable in markerManager. I figured that, if I could remove these, I might have slicker code, whether it fixes the marker problem or not. Thanks.
As a PHP coder, you're accustomed to array keys being fairly arbitrary. In JavaScript however, if you assign an array element numerically that doesn't exist, the array will be allocated with empty elements up to the one you created. That's the behavior you found. Objects, on the other hand, denoted by {} rather than [], accept arbitrary property names (with caution) and function a little more closely to how you're accustomed PHP's array structures functioning. This is not to say that JavaScript objects (or object literals) are a direct analogue to PHP arrays....
If what you want is a data structure with a key called "10", that is a job for an object literal (though it isn't great practice to name object properties numerically.
var fred = {};
fred["10"] = 1;
Note, the more normal syntax of dealing with an object literal is the object.property notation, but that is not valid for numeric properties:
// name as a property
fred.name = "fred";
// Syntax error...
fred.10 = 10;
// Use [] notation for numeric properties:
fred["10"] = 10;
Object literals do not have a length property, however. So you cannot do:
fred.length;
// undefined
You may use an object instead of an array, but you loose some of the benefits of an array, like access to a length property.
<script type="text/javascript">
var fred = {};
fred['10'] = 1;
// alert(fred.length); // won't work anymore
</script>
On the other hand no extra entries will be generated and the access to a specific value works almost the same way as in an array. If you want to traverse all values, use the following:
for( var el in fred ) {
if ( fred.hasOwnProperty( el ) ) {
alert( fred[ el ] );
}
}