I'm developing an HTML5 canvas game, and I have an array of images which are being drawn to the canvas. The images from the array are currently all being drawn correctly, and I have a console.log line which I want to use to display the size of the array in the console. But for some reason, the console keeps telling me that the array length is undefined.
The line I'm using to print the array length is:
console.log("sources array length = " + sources.length);
it's in a for loop:
for (index=0;index < numImages ;index++){
console.log(index);
images[index] = new Image();
images[index].src = sources[index];
console.log("Adding " + sources[index]);
callback(images[index]);
console.log("sources array length = " + sources.length);
}
As you can see, I have another console.log statement in the loop, to log each time the loop is run...
console.log(index);
This line prints the value of the variable index each time the loop is run, starting at 0, and increasing by 1 each time until the loops ends when it reaches the value equal to the variable 'numImages'.
But, for some reason, the line that should be printing the array length is displaying "sources array length = undefined" each time the loop runs, and not the actual length of the array.
Can anyone point out to me why this is? How can I make it display the length of the sources array each time the loop is run?
Edit 13/02/2013 # 15:10
The sources array is defined in the same file, using the line:
var sources = {};
The reason I have not defined a set length for the array, is because I need its length to by dynamic. I have then added elements to the array using lines like this:
sources[0] = document.getElementById("building").src,
sources[1] = document.getElementById("chair").src,
sources[2] = document.getElementById("drink").src,
sources[3] = document.getElementById("food").src,
So what I want my console.log line to do, is tell me the length of the array as it currently is, i.e. how many elements have been added to it. As you can see in the first bit of code I had in my original post, I have a console.log which prints a message to the console every time an element is added to the sources array- they clearly are being added properly, as otherwise, they wouldn't be displayed on the canvas... so the array must have a length which is defined at the point that the images are drawn to the canvas, otherwise they wouldn't be in the array to be drawn.
But, for some reason, the line that should be printing the array length is displaying "sources array length = undefined" each time the loop runs, and not the actual length of the array.
...which tells us that sources doesn't have a length property, and thus is not an array. It's entirely possible to build something that isn't an array but which nevertheless has properties with names like 0, 1, etc. For instance:
var sources = {0: "zero", 1: "one", 2: "two"};
console.log(sources[0]); // "zero"
console.log(sources.length); // "undefined"
If you're getting sources by outputting some server-side information, it may well be being output in the form above (a plain object with numeric property names, which probably would be in quotes) rather than as an actual array, which would look like this:
var sources = ["zero", "one", "two"];
Re your edit
The sources array is defined in the same file, using the line:
var sources = {};
The reason I have not defined a set length for the array, is because I need its length to by dynamic. I have then added elements to the array using lines like this:
sources[0] = document.getElementById("building").src,
sources[1] = document.getElementById("chair").src,
sources[2] = document.getElementById("drink").src,
sources[3] = document.getElementById("food").src,
That's not a problem, JavaScript arrays are dynamic (in fact, they're not really arrays at all — or at least, the standard kind aren't, there are newer typed ones that actually are arrays). So just change
var sources = {};
to
var sources = [];
to make it actually an array. Then you can add to the array the way you are already doing it (that's absolutely fine) or you can use sources.push(document.getElementById("chair").src); and such instead.
Related
Recently i had to make an Array with values at large indexes (due to plugin constraints).
eg:
var names[100000] = "a";
var names[150000] = "b" ... and so on till 5 large indexes.
and in between all values are undefined names[100001] //undefined.
Now my doubt is Since the array has only 5 elements but if i do
names.length //it is 300001
its a large Array. I am not iterating this array nor i am running any loop through it. I will get the values directly through their defined indexes from the array.
So will this structure make any significant performance differences on the Browser or is it alright to use this as long as the number of values in the array is less irrespective of its indexes and no iteration is involved.
Thanks
The only thing that differentiates an array from a plain object is its length property and how it behaves (and a few array specific methods of course). The length value simply increases with certain operations, like setting a numeric property or pushing a new element. That's it in a nutshell. The array doesn't actually contain 100000 elements when you set the property 100000 to a value, all that's happening is that you're setting one property and the value of length is adjusted accordingly.
So, no, it won't have a lot of impact on performance, unless somebody actually iterates through the array using for (let i = 0; i < arr.length; i++).
You can create an array with the length, given by your plugin and work locally with an object to limit the iterations. After all your processing has been applied, you copy the values to the array and send it to the plugin's function.
Keep an array with the desired length as a buffer
var buffer = new Array(20000);
Internally work with an object
var data = {};
Assign values to the object
data[10001] = "foo";
Once transformations or data processing has been applied to the object, copy data to the buffer
for (key in data){
buffer[key] = data[key];
}
Send buffer to the plugin. And clear data, if desired.
By doing so, you will not iterate more, than the actual data you processed.
I got a problem with this simple piece of code which i cant figure out.
Instead of printing the whole array in the console, i get the message "10 undefined". Altough if i put "var i" to 0 or below then it's all good and i get a full list from that number up to 10.
Why wont this work when "i" is set to a number above 0?
Took a picture of my console in chrome to show how it looks like:
var ar = [];
for (var i = 1; i <= 10; i++) {
ar.push(i);
console.log(ar[i]);
}
JavaScript array indices start at 0, not 1. The .push() method adds an element at the end of the array, which in the case of an empty array (as yours is when your loop begins) will be array element 0.
Your loop inserts the value 1 at array index 0, the value 2 at array index 1, and so forth up to the value 10 at array index 9.
Each of your console.log(ar[i]) statements is trying to log a value from an index one higher than the highest element index, and those elements will always be undefined. So the console logs the value undefined ten times.
You can log the last element of an array like this:
console.log(ar[ar.length-1]);
Or in your case where you (now) know that i will be one higher than the index that .push() used:
console.log(ar[i-1]);
"10 undefined" means that the console showed "undefined" 10 times.
As thefourtheye says in his comment, you're pushing the value i but the index of the element that you just pushed onto the end of the array is i - 1. This means that each time you console.log(ar[i]) you're logging something that's not yet defined.
This is all because the first element in the array is ar[0], not ar[1]. You can fix your problem by logging like so: console.log(ar[ i - 1 ]);
Because array indices start at zero. The current index is undefined that's why you get those. Try this instead:
var ar = [];
for(var i = 1;i <= 10;i++){
ar.push(i);
console.log(ar[i-1]);
}
I would like to read some text, consisting of triads of comma separated numbers with one triad per line, into a 2D array. I do not know in advance what the array dimensions will be. I use the following code.
// Read data into a matrix
var inputData = [[]];
while (allTextLines.length>0) {
dataRecord=allTextLines.shift();
entries = dataRecord.split(',');
var xCoord=parseInt(entries.shift());
var yCoord=parseInt(entries.shift());
var zCoord=parseInt(entries.shift());
if (yCoord>=inputData.length) inputData[yCoord]=[];
inputData[yCoord][xCoord]=zCoord;
}
This results in
TypeError: can't convert undefined to object
from Firebug when I try to call
if (yCoord>=inputData.length) inputData[yCoord]=[];
or
inputData[yCoord][xCoord]=zCoord;
I thought that JavaScript arrays could be dynamically resized by assigning a value to an index higher than the current size.
They can be dynamically resized when they exist. There's no such thing as a 2D array in JavaScript. What you create in your initialization is a 1D array with an array in the first element.
All you have to do is check the first dimension before adding something in the second dimension. You're almost doing that now, so it's a minor change:
if (inputData[yCoord] == null) inputData[yuCoord] = [];
You have to do that instead of just checking the length because, if "yCoord" is initially 3, then positions 0, 1, and 2 would still be null after you initialize position 3. Subsequently, a "yCoord" value of 2 would fail your length check, but the slot would be empty nevertheless.
Alternatively, you could do something like this:
for (var yplus = inputData.length; yplus <= yCoord; inputData[yplus++] = []);
It seems like JavaScript somehow tries to optimize code, so if we want to fill a multidimensional array (largeArr) with changing values of one-dimensional array (smallArr) within a loop and use this code:
largeArr = []
smallArr = []
for (i=0; i<2; i++)
{
smallArr[0]=i
smallArr[1]=2*i
largeArr[i]=smallArr
}
we get an unexpected result: largeArr=[[1,2],[1,2]] (must be [[0,0],[1,2]]). So, Javascript calculates smallArr values in the first place, and only then fills largeArr.
To get the right result we must declare smallArr in the loop:
largeArr = []
for (i=0; i<2; i++)
{
smallArr = []
smallArr[0]=i
smallArr[1]=2*i
largeArr[i]=smallArr
}
and then it works as expected (largeArr=[[0,0],[1,2]]).
Why does it behave this way?
Because Pointers, that's why. Javascript takes after Java, and C, in this (and only this) way. When you do the assignment
largeArr[i] = smallArr
you're assigning a pointer. A breakdown of pointers:
In C, (and to a lesser extent, Java and Javascript) you don't have a basic array type - instead, an array points to a space in memory, and you can fill that space with whatever information you want (or rather, you've declared). The way a pointer exists in memory? A four (or eight, or two, depending on your system) byte memory address, which tells the compiler/parser where to get the appropriate in formation. So, when you do that assignment there, you're telling it: "Hey, set largeArr[i] equal to the memory address of smallArr." Thus, when you make changes to smallArr, it's reflected every time you dereference the array - because it's actually the same array. But when you do:
smallArr = []
inside the loop, you're saying, "make a new array, and set smallArr equal to the address of that array." That way, the arrays stay separate.
With the line largeArr[i]=smallArr, you set the i property to a reference to the smallArr. You do not copy it. In the end, all properties of the largeArr will point to the same one smallArr, where you have overwritten the values each time.
By initializing the smallArr each loop turn, you create new objects; so each property of largeArr will point to a different array. Btw, it is an assignment, not a declaration - you would (and should) declare the variables as local (to the function) with a var statement.
In the last for iteration
smallArr[0]=i
smallArr[1]=2*i
(where i=1) the above code is transformed into :
smallArr[0]=1
smallArr[1]=2
And your big array is nothing than this :
[smallArr, smallArr]
which leads to the unexpected result :
[[1, 2], [1, 2]]
In javascript objects are copyed by reference (a kind of c style pointer).
In order to have the desired result, you must copy the array by value, or assign a different array in each loop :
var largeArr = [];
for (i=0; i<2; i++)
largeArr[i] = [[i, 2*i]];
When you assign an array reference as you have above, you're not assigning the values of that array, but just a reference to the array.
Think of it as a pointer. largeArr[0] and largeArr[1] are pointing to smallArr, and the loop iterations are simply changing the contents of smallArr. The thing to which largeArr is being "pointed" is not changing.
I have an OOD system for my current webApp that every element has an id and is placed in the elements array of each page. the id of each new element is a continuous number regardless of the page that the elemenet is placed at, so for example if we have 25 elements in a project that has 7 pages, the ID of the new element no matter which page it's placed will be 26.
So for example page one of a project that has 2 elements in it with IDs of 1 and 4 will be :
[undefined, proto.constructor, undefined, undefined, proto.constructor ]
this way refrencing an element would be very easy because all I need is the page number and ID of the element and I can call the element, for example pages[1].elements[1]. But the problem that I have with this method is that it results in excessive number of "undefined" elements in the final JSON which makes the JSON too big unnecessarily. Is there any way around that ?
Use a JS object instead of an array. It can still have numeric-looking keys (they're actually strings, but that's true for arrays, too) and has the same constant-time lookup benefits.
So, instead of code like this…
var objectsById = [];
objects[object.id] = object;
…instead write code like so:
var objectsById = {};
objects[object.id] = object;
The JSON output will be terse (though not necessarily sorted):
{ "42":"someserializablevalue", "17":"another JSON value" };
add a string like '_' at the end or the beginning of the assignation
var id=2
var array['_'+id]=value
in hits way instead of indexing and mapping all the elements the away will be assigned as an associative array ob elements
Why not initilizing the array members with an empty string
like this:
var arr = ['','','','','','','','','',''];
or like this:
var arr = new Array(10);
for(i=0;i<arr.length;i++)
arr[i]='';