JSON array with properties - javascript

I have the following js array/object
var x = [1,2,3,4];
x.name = "myArray";
I am using json2.js and I am trying to serialize x in a string.
and all I get is the array:
[1,2,3,4]
is that correct ?
since I can add any property to an array why doesn't json2 handle that ?
what am I missing ?

First of all json2.js ignores properties in the array.
if it had not to ignore them then it would be impossible to have an array in json format which should be easy to eval.
Let's imagine we come out with something like:
[1,2,3,4]{name:'test',anotherProperty:'someValue'}
if the above was valid javascript to create an array and stick two properties then it would be great and we could json-it.
It would be equivalent to do this:
array = [1,2,3,4]
array.name = 'test';
array.anotherProperty = 'someValue';
But it is not and that's the reason why we can not persist into json.

What were you expecting to see? :) I'm not sure what you're trying to do.
x is an array and all you did when you did x.name, you simply set up a property called name for the array object. The name property itself is not added into the array. You can see this in firebug:
The array object has a property called name, but the value of that property is not added to the array itself.
What you want to do is something like this:
var x = {
array: [1, 2, 3, 4],
name: "myArray"
};
Now you have an object called x that has two properties. The array property refers to an array, and the name property refers to the name. x.array will give you the array, and x.name will give you the name.
EDIT
This is in response to your comments. While it is true that arrays can be enriched with properties, think about what it means when you have to serialize that object. What exactly do you want to see when you serialize x? If x is already the array [1, 2, 3, 4], how would you represent it in JSON? You could represent it as:
{ 0: 1,
1: 2,
2: 3,
3: 4,
name: "myArray"
};
But what you now have is no longer an array. Also, the array object itself has a bunch of native properties. How should a JSON serializer handle those?
I think you're mixing up an array as an object and an array as a literal. An array as a literal is just [1, 2, 3, 4]. Now internally, the array as an object presumably has some property that points to the actual value of the array. It also has other properties (like length) and methods that act upon it (like slice).
The JSON serializer is concerned with the value of the object. If x is an array, then the thing that must be serialized is the value of x, which is [1, 2, 3, 4]. The properties of x are entirely different.
If you want to serialize these additional properties, then you would have to write your own serializer that will iterate over the properties of the array and represent everything in a map/associative array. This is the only way; the caveat, as I mentioned before, is that you no longer have an actual array.

The problem is json2 still believes it's an array since x instanceof Array returns true. To fix it, you could create the "array" in a roundabout way:
var x = {
0: 1,
1: 2,
2: 3,
3: 4,
length: 4,
name: 'myArray'
};
The problem with this solution is that none of the array methods will be available on the object. So if you ever need to use pop, push, etc, you'll have to convert it to a real array with Array.prototype.slice.call(x); or if you're byte hungry [].slice.call(x);.

Not sure why you would do it, but a for in loop would get everything
var x = [1,2,3];
x.name = "wtf";
for(var y in x){
console.log(y + ":\t" + x[y]);
}
Produces:
0: 1
1: 2
2: 3
name: wtf
but json2 code will not see it this way, why don't you convert it over to an object?

Related

How can I get results of arrays in many Objects in Angular or Javascript?

I need a help in this question:
I have objects with arrays. I need get the values in the arrays to send to the server.
My question in Image:
This is the code I print in the console:
var cart = sharedCartService.cart;
console.log(cart);
How I can get this datas?
In javascript either you put values in an array:
var array = [1, 2, 3, 4];
that can be objects:
var array [
{id: 1},
{id: 2}
];
But you can't put key value pairs in an array
// not valid
var array = [id: 1, name: sdf];
Only objects can have key value pairs, arrays only have values.
In your json the keys add, decrement, find, etc are key value pairs and making your array not valid.
What you need to do is to put those in a third object or make the whole thing an object by replacing [] by {}
Once you have a valid object or array you can use for in to loop over the properties of your object or calling them directly with the dot notation or looping through the objects in your array.
https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Instructions/for...in

How to filter Object using Array.prototype.filter?

Given
var arr = [1,2,true,4,{"abc":123},6,7,{"def":456},9,[10]]
we can filter number items within array arr using Number constructor
var res = arr.filter(Number); // [1, 2, true, 4, 6, 7, 9, Array[1]]
are true and [10] expected in resulting array ? If we substitute false for true at arr
var arr = [1,2,false,4,{"abc":123},6,7,{"def":456},9,[10]]
var res = arr.filter(Number) // [1, 2, 4, 6, 7, 9, Array[1]]
using Array.isArray
var res = arr.filter(Array.isArray) // [Array[1]]
String
var res = arr.filter(String) // [1, 2, true, 4, Object, 6, 7, Object, 9, Array[1]]
If we want to filter items within arr that are object, at indexes 4 , 7 and we try
var res = arr.filter(Object) // [1, 2, true, 4, Object, 6, 7, Object, 9, Array[1]]
Although we would prefer to simply call arr.filter(Object), we could pass a function call; trying different properties of Object so that we can eventually find a property or method that we could use as a function or constructor to pass to as the pattern arr.filter(/* method, constructor, other approach */) to return the filtered results matching the object, or even property name or value of the object within the input array.
We start, innocently enough, by checking if the item in the array has a constructor having name equal to "Object"
var res = arr.filter(function(prop) {
return prop.constructor.name === "Object"
}) // [Object, Object]
though when we add an object to arr; e.g.;
var c = Object.create(null); arr.push(c);
var res = arr.filter(function(prop) {
return prop.constructor.name === "Object"
}) // `Uncaught TypeError: Cannot read property 'name' of undefined`
as c prototype and constructor are undefined. Although we are certain that this will not return expected results
var n = arr.filter(Object.hasOwnProperty, "abc"); // [1, 2]
at least an error was not returned; let us continue
var n = arr.filter(function(prop, val) {
return prop.hasOwnProperty(this.valueOf())
}, "abc"); // [Object abc: 123__proto__: Object]
the expected results are returned; though we are trying to use
var n = arr.filter(/* function reference */, this /* optional parameters passed */)
to
filter an array for Object : {} objects; even if the object does not have a defined prototype or constructor; optionally converting JSON string "{"abc":123}" to object; though we have not reached this far, yet;
pass a property name to .filter(callback, this) pattern where this serves as property name, or value of object; or utilize an approach using filter.bind , .call or .apply or other method to filter an object from the input array - without using full
.filter(function(prop, value) {})
pattern. How can we coerce the Object.hasOwnProperty() call into a pattern similar to
.filter(Object.hasOwnProperty, "abc")
?
Mentioning .call, .bind and .apply after searching for a similar Question and finding JS Array.prototype.filter on prototype method . Though not certain how to implement approaches described in filtering both objects and objects having specific properties as described above.
Note, Question can also be resolved by a destructuring , or other es-6, es-7 approach, providing comparable or, even stricter results, when compared to .filter(). That is, use .filter() without
function(prop, value) {
}
pattern. Returning objects; that is Object , {} ; and objects filtered by property ; objects filtered by property value.
Questions:
How to filter objects with or without Object prototype or constructor within in an array passed to Array.prototype.filter() without using an anonymous function callbackpattern ?
How to filter specific objects within an array passed to Array.prototype.filter() by passing property name or value to match object without using anonymous function callback pattern ?
How to filter objects with or without Object prototype or constructor
within in an array passed to Array.prototype.filter() without using an
anonymous function callbackpattern ?
As per spec
callbackfn should be a function that accepts three arguments and
returns a value that is coercible to the Boolean value true or false
Number object (function's constructor) does return NaN for bad Number conversion but String and Object constructors don't return a false value (yes, filter(Number) also filters out 0)
var arr = [0,1,2,true,4,{"abc":123},6,7,{"def":456},9,[10]];
arr.filter(Number); //outputs [1, 2, true, 4, 6, 7, 9, Array[1]]
You can create a customer function OBJ,
function OBJ(value,index,arr){ return typeof value === "object" && !Array.isArray(value) }
or Arrays are also welcome in the resultset then remove the Array.isArray check
function OBJ(value,index,arr){ return typeof value === "object" }
when used with
arr.filter(OBJ); //outputs [{"abc":123},{"def":456}]
There is no real way to do it safely without creating your own function. Additionally it is very complicated because the definition of Object is too broad.
Let's start with the following:
var types = ['1', 2, true, null, undefined, [], {}, new Date()];
and run the following:
types.map((e) => typeof e);
// ["string", "number", "boolean", "object", "undefined", "object", "object", "object"]
Do you think of null of as an Object? I don't think so. Do you think of an Array as of an Object, because the Array is an instance of Object? I am not sure as well.
What you can try is the following:
types.map(Object.isExtensible);
// [false, false, false, false, false, true, true, true]
This excludes the null from the result but still the array is present here. The Date Object is here as well as any other Object with any prototype, e.g. new Boolean() will also be an Object. Additionally the object could be frozen and this won't be returned as an Object here as well.
So the both examples here successfully demonstrate that the definition of Object is too broad and it cannot be really handled in a useful way.
You seem to want to filter an array for elements with a certain type. Pass an appropriate function to filter:
array.filter(istype("String"))
You just need to write istype now:
function istype(type) {
return function(x) {
return Object.prototype.toString.call(x) === '[object ' + type + ']';
}
}
You seem to have thought you could filter for numbers by saying filter(Number) etc. But that will not work. Number is just another function, which tries to turn something into a number (not check if it's a number). Then, filter filters the array depending on whether the result is truthy or falsy. Number will produce a truthy value for any non-zero number obviously, and true. For a string, or an object, or pretty much anything else, it will return NaN, which is falsy, with odd exceptions such as returning 0 for [] or an all-blank string.
Same with string. String is just another function, which tries to turn something into a string. Then, filter filters the array depending on whether the result is truthy or falsy. String will produce a truthy value for almost anything other than a non-empty string.
This has nothing whatsoever to do with destructuring; why would you think it does? You might want to remove that unfortunate part of your post. Nor is it clear what you mean by "calling filter without a callback"--using a callback to determine which elements to filter in and out is the entire DNA of filter. It is also unclear what pattern you are referring to when you say function(prop, value) { } pattern.
At the end of your question, you ask two specific questions:
How to filter objects with or without Object prototype or constructor within in an array passed to Array.prototype.filter() without using an anonymous function callbackpattern ?
You filter objects from an input array by providing a function which determines if a particular element is an object. That is not what the object prototype or constructor Object is, so that won't help you. You have to write a little function to pass to filter, that's how it works. It could be anonymous, or it could be defined elsewhere and passed in
How to filter specific objects within an array passed to Array.prototype.filter() by passing property name or value to match object without using anonymous function callback pattern ?
What do you mean by "passing property name or value to match object"? Do you mean, filter out elements which are missing a particular property name or value? Then write a function to do that. There is no built-in function for this purpose, if that is what are looking for.
Without passing a callback function, you can instead pass in a regex by using the RegExp.prototype.test method and binding a regex
var arr = [1,2,true,4,{"abc":123},6,7,{"def":456},9,[10]]
var res = arr.filter(RegExp.prototype.test.bind(/\[object Object\]/));
console.log(res)
This would match any string containing [object Object] as well, but it seems highly unlikely that a string would contain those exact words, unless you have made a mistake and included stringified objects in your array.
In ES6 the following would do it for the example values you have listed:
arr.filter(Object.isExtensible)
Obviously, this will exclude objects that have been marked non-extensible, by a call to Object.freeze, Object.seal, or Object.preventExtensions. Unless you plan to use those, I believe this does the job.
var arr = [
/* primitives: */
2, true, "str", null, undefined, NaN,
/* objects */
new Number(2), {a:1}, Object.create(null), [10], x=>x, new Date(), new Set()
];
var objects = arr.filter(Object.isExtensible);
console.log(objects);
The closest have been able to reach to requirement so far, also matches Object.create(null)
var res = []; for (let p of arr) /^\{?.+\}$/.test(JSON.stringify(p)) && res.push(p)

Is an array in JS actually filled with empty spaces or when printed is it filled with zeros?

I have an array:
mydata =[];
i am storing values in the array by using a numeric key that can be somewhat big
mydata[13525] = 1;
However if i only store one item as the above, when i print the array in the console it prints 13524 commas before the object, nevertheless the debugger tells me it has length 13526 and there is only one element in the array.
I am confused as i understood that JS arrays do not required every position to be filled and certainly this might consume a lot of memory on bigger numbers. Can you explain please?
The .length property of an array represents the highest index plus one in the array that has been assigned a value.
When you do not assign intermediate values (and thus have a sparse array), the intervening values that you have not assigned are undefined which is essentially the "nothing here" value in Javascript. The console chooses to display arrays by trying to show you every value between 0 and the end of the array which is simply not a very good way to display a sparse array that is mostly empty. That's more an artifact of a design choice in the console than anything else. One could design a different way to display contents of an array that would handle sparse arrays differently.
Arrays are most efficient if you use consecutive indexes started from 0. That's what they are mostly designed for and what many implementations are optimized for since a runtime can do some optimized things if it knows there is a sequential set of values.
If you know you're going to mostly not be using sequences of numeric indexes starting from 0 and as such the .length property is of little use to you, then perhaps a plain object with arbitrary properties is a better choice.
var mydata = {};
mydata[13525] = 1;
console.log(mydata[13525]); // 1
console.log(mydata.length); // undefined - no .length property on an object
console.log(myData); // {1: 13525}
If you only want to print any non-null value in the array, instead of printing the whole array I'd use a for loop that only prints non-null values. It'd be something like this...
for (i = 0; i < mydata.length; i++) {
if(mydata[i]!= null){
console.log(mydata[i]);
}
}
javascript array is bit different from others,
var foo = [1, 2, 3, 4, 5, 6];
foo.length = 3;
foo; // [1, 2, 3]
foo.length = 6;
foo.push(4);
foo; // [1, 2, 3, undefined, undefined, undefined, 4]
While the getter of the length property simply returns the number of elements that are contained in the array, in setter, a smaller value truncates the array, larger value creates a sparse array. Guess what the setter mydata[13525] = 1; would do.
src: Javascript Garden
Edit:
to print/use only the values present, you can do
mydata.forEach(function(v){console.log(v);});

Initialize an array whose indexes are scattered over integer range

How to initialize a string array (size<100 items) in javascript whose indexes are scattered over entire integer range, with data items.
If I do like this:
array1 = ["string1","string2","string3","string4"];
then I get array of length 4 with indices ranging 0 to 3
But in my case i want to keep my own indices, so that the array could be used like a high performance int-string hash table.
I'm preferably looking out for a single statement initialization.
The items of the array should be accessible like this: array1[23454]
Update From Comments
I'm restricted to initialize the array as a single statement since a dynamically prepared array initialization string is appended from server side like this: var array = <string from server here>
To create an array with a set number of indexes you can use
// Creates an array with 12 indexes
var myArray = new Array(12);
This isn't needed in javascript due to the way its array's work. There isn't an upper-bound for arrays. If you try to reference an item index in the array that doesn't exist, undefined is returned but no error is thrown
To create an array with perscribed indexes you can use something like array['index'] = value though this would force you to use multiple statements. Javascript doesn't have an array initalizer to allow for you to specify indexes and values all in a single statement though you can create a function to do as such
function indexArray(param) {
var a = [], i;
for (i=0; i<param.length; i+=1) {
a[param[i].index] = param[i].value;
}
return a;
}
var myArray = indexArray([
{ index: 123456, value : "bananas" },
{ index: 12, value : "grapes" },
{ index: 564, value : "monkeys" }
]);
var array1 = []
array1[23454] = 2
Just doing this should be fine. There's no set array size for javascript in the way there is for java.
If you really want to do this all in a single statement, you can make an object instead like this:
var object1 = {
"23454":2,
"123":1,
"50":3
};
and then retrieve the numbers like this:
object1["23454"] //2
I don't really recommend this though. The array method is a cleaner way of doing it even if it takes multiple lines since it doesn't require string conversion. I don't know enough about how these are implemented in browsers to comment on the performance impact.
Update
Since the 1 line requirement is based on something being passed to the server, I would recommend passing a JSON object to the server in the form:
"{"23454":2,"123":1,"50":3}"
then this code will parse it to an object:
var object1 = JSON.parse(jsonstringfromserver);
and if you like you can always convert that to an array by enumerating over the properties with a for in loop:
var array1 = []
for ( num in object1){
array1[num] = object1[num];
That is probably unnecessary though since object1[123] will already return 1. You only need this if you plan on doing array specific operations.
You don't have to pre-define the size of an array before you assign to it. For example:
var _array = [];
_array[0] = "foo";
_array[1000] = "bar"; // _array.length => 1001
_array[1] //undefined
No need to initialise the appropriate number of array elements before you assign to them.
Update
It already has been pointed out that you can use an object rather than an array. However, if you want to take advantage of array methods then this is still possible. Let me give you an example:
var obj = {
0: 15,
1: 10,
2: 5,
length: 3
};
If the object contains a length property then it can be treated as an array-like object. Although you can't call array methods directly from these objects you can use array methods.
Array.prototype.join.call( obj ); // 15,10,5
In fact using the ECMAScript 5 map function you can easily convert the above object to an array.
var _array = Array.prototype.map.call( obj, function( x ) { return x; } );
The map function does not exist in all browsers but you can use the following function if it doesn't.
Array.map = Array.map || function(a, f, thisArg) {
return Array.prototype.map.call(a, f, thisArg);
}
You can do what you want with an Object in this way:
var o = {23454: 'aaaa', 23473: 'bbb'};
You will lose the array methods/fields, e.g. length, but you will gain what you said you are looking for, and you will be able to add/remove members easily.

Issue Reversing Array of Objects with JS

I'm parsing JSON and getting an array of objects with javascript. I've been doing this to then append an element for each object:
for(o in obj){ ... }
But I realized that for a certain situation I want to go backwards through the array. So I tried this before the for loop:
obj = obj.reverse();
However this isn't reversing the order of the objects in the array. I could simply put a count variable in the for loop to manually get the reverse, but I'm puzzled as to why reverse doesn't seem to work with object arrays.
There's no such thing as an "object array" in JavaScript. There are Objects, and there are Arrays (which, of course, are also Objects). Objects have properties and the properties are not ordered in any defined way.
In other words, if you've got:
var obj = { a: 1, b: 2, c: 3 };
there's no guarantee that a for ... in loop will visit the properties in the order "a", "b", "c".
Now, if you've got an array of objects like:
var arr = [ { a: 1 }, { b: 2 }, { c: 3 } ];
then that's an ordinary array, and you can reverse it. The .reverse() method mutates the array, so you don't re-assign it. If you do have an array of objects (or a real array of any sort of values), then you should not use for ... in to iterate through it. Use a numeric index.
edit — it's pointed out in a helpful comment that .reverse() does return a reference to the array, so reassigning won't hurt anything.
That's because the for (o in obj) doesn't iterate the array as an array, but as an object. It iterates the properties in the object, which also includes the members in the array, but they are iterated in order of name, not the order that you placed them in the array.
Besides, you are using the reverse method wrong. It reverses the array in place, so don't use the return value:
obj.reverse();

Categories