Are there cases in which Array.isArray() doesn't work? - javascript

So I've been trying to debug a physics engine I'm writing, and for a multi-dimensional spatial hashmap I'm needing to allocate a 2D array of arrays.
Why does this code give me "Cannot read property 'push' of undefined"? Is there something happening in the line between my if statements and my trying to push on to the array?
EDIT "this" refers to a PhysicsEngine instance, it keeps a reference to the "entities" array as well as a "hashmap" array.
function PhysicsEngine(game) {
this.game = game;
this.entities = [];
this.hashmap = createArray(32, 32);
}
for(var i = 0; i < this.entities.length; i++) {
//Array item may not be a Simulateable Entity
//this.entities[i].simulatePhysics(this);
this.entities[i].ResolveCollisions();
this.entities[i].Move();
hmx = Math.round(Math.abs(this.entities[i].x/32));
hmy = Math.round(Math.abs(this.entities[i].y/32));
if(!logged) {
console.log(this.hashmap);
console.log(this.entities[i]);
console.log(i, hmx, hmy);
console.log(this.hashmap[hmx], this.hashmap[hmy]);
logged = true;
}
if(!Array.isArray(this.hashmap[hmx])) {
this.hashmap[hmx] = [];
if(!Array.isArray(this.hashmap[hmx][hmy])) {
this.hashmap[hmx][hmy] = [];
}
}
this.hashmap[hmx][hmy].push(this.entities[i]);
}

I think that this code:
this.hashmap[hmx] = [];
if(!Array.isArray(this.hashmap[hmx][hmy])) {
this.hashmap[hmx][hmy] = [];
}
is not correct. In particular, the "if" condition tests whether this.hashmap[hmx][hmy] is an array. The problem is that this.hashmap[hmx]=[] (as you have set one line before), so this.hashmap[hmx][hmy] is undefined and javascript throws an error "Undefined is not an object".
Maybe is this the problem?

Related

Cannot set properties of undefined by iteration the nested JSON

I have a nested JSON, this is structured as follows:
As you can see the JSON is called bwaResult and in this object there are three big groups. These groups are called actBwa, fcBwa and planBwa. These groups contain years and yearlyResults(sums) which also have years. I would like to assign the values to the individual years. That means in 2020 you would have actBwa, fcBwa, planBwa and the yearlyResults values and the same for the other years.
My Code:
const plMonthResults = {};
const plMonth = resp.success ? resp.bwaResult : null; // JSON-DATA
delete resp.success;
if (plMonth && plMonth !== null && Object.keys(plMonth)) {
let count = 0;
for (const bwaType in plMonth) {
const plMonthData = plMonth[bwaType]; // Here I get actBwa, fcBwa, planBwa
if (count === 0) {
for (const yearKey of Object.keys(plMonthData)) {
plMonthResults[yearKey] = {}; // Sort by years
}
}
for (const yearKeyInPlMonth in plMonthData) {
plMonthResults[yearKeyInPlMonth][bwaType] = plMonthData[yearKeyInPlMonth]; // Here then arises the error
}
count += 1;
}
}
When I run the code then I get the following error:
ERROR TypeError: Cannot set properties of undefined (setting 'fcBwa')
I guess since actBwa only has 2020 and the other groups have more years there is a problem finding fcBwa and iterating further or am I seeing this wrong? Can you tell me how to solve this problem?
UPDATE my work in stackblitz: https://stackblitz.com/edit/read-local-json-file-service-udqvck?file=src%2Fapp%2Fapp.component.ts
It seems like you're using count to copy the keys only once, but that means you will only have the keys of the first object (in this case actBwa). You can instead go through the key of each object, but make sure you don't override the existing ones. So remove the count and modify the look like this
for (const yearKey of Object.keys(plMonthData)) {
plMonthResults[yearKey] = plMonthResults[yearKey] ?? {};
}
You can even remove this loop and include the check into the main one:
for (const yearKeyInPlMonth in plMonthData) {
plMonthResults[yearKeyInPlMonth] = plMonthResults[yearKeyInPlMonth] ?? {};
plMonthResults[yearKeyInPlMonth][bwaType] = plMonthData[yearKeyInPlMonth];
}
Let me know if that gives you the result you're after

Problems with immutable array

Recently i started working with D3.js to plot a sunburn graph. The data is provided in JSON. For some design stuff i wanted to swap some items (called childrens in D3 doc).
I know in JS arrays are objects...so something like this:
var buffer = myarray[2];
is just a reference. Therefore a buffer for swapping has no effect (?).
Thus i invented a second array (childrens_final) in my code which adopt the items while the swapping process. Its just iterating through every item, a second iteration is looking for an item with the same name to set items with same name in a row. Therefore the swap.
var childrens = response_data.data.data['children'];
var childrens_final = []
for (var child = 0; child < childrens.length; child++) {
var category = childrens[child];
var found = false;
var i = child+1
while (!(found) && (i < childrens.length)) {
if (childrens[i]['name'] == category['name']) {
var childrens = swapArrayElements(childrens, child+1, i);
var one = childrens[child];
var two = childrens[child+1]
found = true;
}
i++;
}
if (found) {
childrens_final.push(one);
childrens_final.push(two);
child++;
}
else {
childrens_final.push(childrens[child])
}
}
response.data.data['children'] = childrens_final;
return response.data.data;
The function swapArrayElements() is just using splice:
function swapArrayElements(list, x, y) {
if (list.length ==1) return list;
list.splice(x, 1, list.splice(y,1, list[x])[0]);
return list;
}
The problem is that there is still no effect from the swap in the graph. But when logging the childrens_final. There is something like that in the console:
Array [ Object, Object, Object, Object, Object, Object, Object, Object, Object ]
The objects are in the right order! But in the array there is still the old order.
Thats actually so basic, but i dont see a solution.
Btw...the code is working under AngularJS.
Found the problem. It's a D3.js problem. D3 is sorting the data itself. You have to set explicitly:
d3.layout.partition.sort(null)
Otherwise every pre sorting process has no effect.

getElementByID loop returning null

Chrome developer tools says that the value function doesn't work on a null value and points to the line in the for loop. Why isn't getElementByID fetching my values? (this is a refactor, getElement work perfect with the actual values typed in).
locationStops = ["start","end"];
var stopNum = locationStops.length;
var stopAddresses = [];
for(val in locationStops) {
stopAddresses.push(document.getElementById(val).value);
}
You could avoid the for loop, and the potential for bugs that you ran into with, by using map:
stopAddresses = locationStops . map(function(id) {
return document.getElementById(id).value;
});
Depending on your stylistic preferences, you might find the following more readable:
function get_value_from_id(id) {
return document.getElementById(id).value;
}
stopAddresses = locationStops . map(get_value_from_id);
If you want to use a loop, you could use the new for...of construct:
for (let val of locationStops) {
^^
stopAddresses.push(document.getElementById(val).value);
}
If you have an environment that supports ES7 array comprehensions:
[ for (id of locationStops) document.getElementById(id).value ]
If you want to stick with your for...in loop, then as other answers have pointed out, the loop variable is the index, not the value, so you have to access the ID with locationStops[i], but you are better off using a regular for loop.
Do not use for in for arrays.
Use a simple for loop instead.
var a = ["start", "end"];
for(var i = 0; i < a.length; ++i)
{
console.log(document.getElementById(a[i]).value);
}
You can use for-in also but, it is not recommended as it results in unexpected behaviour sometimes.
val refers to 0,1 etc. So there must be elements with ID's 0,1.
for(var val in a)
{
console.log(document.getElementById(a[val]).value);
}
Your code is not working because your for loop syntax is incorrect
Try This
var locationStops = ["start","end"];
var stopNum = locationStops.length;
var stopAddresses = [];
for(i = 0; i < locationStops.length; i++) {
stopAddresses.push(document.getElementById(locationStops[i]).value);
}
Alternatively, you could use Array.prototype.map.
var locationStops = ["start","end"];
var stopAddresses = locationStops.map(function(val) {
return document.getElementById(val).value;
});
Honestly, though, looping over a two element array is kind of silly and if it was my code I would even prefer to simply assign each address directly.
var stopAddresses = [document.getElementById("start").value, document.getElementById("end").value];

TypeError: Cannot read property 'search' of undefined

hi i'm trying make a simple search using arrays, but i get this error:
TypeError: Cannot read property 'search' of undefined
this is my code:
var debug = [];
var search = function (data, wordSearch) {
"use strict";
var
wordList = [], //set a word lists to send a result.
i = 0,
word,
cutedWord;
debug.push(data);
while (i <= data.length) {
word = data[i];
if (word.search(wordSearch) !== -1) {
wordList.push(data[i]);
}
i++;
}
return (wordList);
};
Take out the = from the <=
while (i < data.length) {
If the array length is 0 its going to do at at least one iteration even though it has no contents, because i<=0 and since the array has no contents data[0] will be undefined, which makes word undefined.
Or if there are contents, it will go past the array bounds, which have the same results

Javascript array in loop

I am trying to loop through all elements in an xml file with the name "playerhash" with javascript.
for(var i = 0; i < 4; i++) {
alert(i);
if(getCookie('riskinfo') == xmldoc.getElementsByTagName("playerhash"[i].childNodes[0].nodeValue) {
player = xmldoc.getElementsByTagName("playerhash")[i].getAttribute('color');
break;
}
}
When I try to run the js it gives me Line 3: Uncaught TypeError: Cannot read property 'nodeValue' of undefined With the alert() function I figured out that the error is occurring when i = 0 and I know that there are at least four playerhash elements.
How can I loop through all of the elements without the error?
As deceze said, you have errors in the code. You should write your code in much smaller steps so that it is easier to debug. Also, check each step before proceeding so that if it fails unexpectedly, it will not throw errors at the user. Condition expresssions should not do assignment as that makes debugging more difficult, use them just for testing conditions:
// Should have already checked that xmldoc is a valid document
var riskinfo = getCookie('riskinfo');
var playerhash = xmldoc.getElementsByTagName("playerhash");
var max = 4; // or playerhash.length
var node, player;
for(var i = 0; i < max; i++) {
node = playerhash[i];
if (node && node.nodeValue == riskinfo) {
player = node.getAttribute('color');
i = max; // break out of for loop
}
}
.getElementsByTagName("playerhash"[i].childNodes[0].nodeValue)
You're missing a ) in there. Should be something along the lines of this:
if (getCookie('riskinfo') == xmldoc.getElementsByTagName("playerhash")[i].childNodes[0].nodeValue) {
Of course, repeating xmldoc.getElementsByTagName("playerhash") in every loop is rather expensive, you should do this once before the loop and save the result in a variable.
You should probably also check whether the ith element actually exists and whether it actually has any child nodes before trying to access that child node.

Categories

Resources