I am calculating row and column of a given point by javascript function.
To achieve this I have to declare global variables
var global_row;
var global_col;
Here is function body
function calculate_city_row_col(cur_city_id)
{
var r = 565;
var c = 1;
var max_city_id = 159895;
do{
if((r%2) == 0) c++;
max_city_id -= r;
r--;
}
while(cur_city_id <= max_city_id)
//Saving Result in seperate row and column
global_row = r + 1; //Global Variable
global_col = c + (cur_city_id - (max_city_id + 1)); //Global Variable
}
Here is function call
var city_id = 1244;
calculate_city_row_col(city_id);
var city_row = global_row;
var city_col = global_col;
Is there anyway to directly pass local variables? (without using global variables)
like this
calculate_city_row_col(cur_city_id, city_row_ref, city_col_ref);
Just return an object:
function calculate_city_row_col(cur_city_id)
{
var r = 565;
var c = 1;
var max_city_id = 159895;
do{
if((r%2) == 0) c++;
max_city_id -= r;
r--;
}
while(cur_city_id <= max_city_id)
return {
row: r + 1,
col: c + (cur_city_id - (max_city_id + 1))
};
}
var rowAndCol = calculate_city_row_col(1244);
var city_row = rowAndCol.row;
var city_col = rowAndCol.col;
Can we pass variables by reference in JavaScript Function
No. JavaScript is purely pass-by-value (the value passed when you pass an object around is an object reference, but it's still a value).
Your options are:
Have the function return an object (or array)
function calculate_city_row_col(cur_city_id)
{
var r = 565;
var c = 1;
var max_city_id = 159895;
do{
if((r%2) == 0) c++;
max_city_id -= r;
r--;
}
while(cur_city_id <= max_city_id)
//Saving Result in seperate row and column
return {
row: r + 1,
col: c + (cur_city_id - (max_city_id + 1))
};
}
Usage:
var result = calculate_city_row_col(someCityId);
console.log(result.row);
console.log(result.col);
Have the function accept a reference to an object (or array) that it updates
function calculate_city_row_col(cur_city_id, result)
{
var r = 565;
var c = 1;
var max_city_id = 159895;
do{
if((r%2) == 0) c++;
max_city_id -= r;
r--;
}
while(cur_city_id <= max_city_id)
//Saving Result in seperate row and column
result.row = r + 1;
result.col = c + (cur_city_id - (max_city_id + 1));
}
Usage:
var result = {};
calculate_city_row_col(someCityId);
console.log(result.row);
console.log(result.col);
Barring a strong reason to go with #2 in a specific situation, #1 is usually the best option. For instance, if you were calling this function thousands of times in a tight loop, there might be a justification for reusing a single object (by passing it in) instead of creating a new object every time.
Related
I'm having issues with pushing object into an array.
I set an object with values and push them to the array. I then change some of the values of the object and push the object into the array again.
However, on inspection, both objects pushed into the array are identical, both object's values are identical to the last object that was pushed into the array.
let ProductPosition = function (x, y) {
this.x = x;
this.y = y;
}
let PalletType = (function () {
function PalletType() {
this.PatternType = '';
this.ProductWidth = 0;
this.PalletWidth = 0;
this.ProductPositions = [];
}
});
function getPalletPositions(pallet, pattern) {
pal.ProductPositions = [];
let posn = new ProductPosition();
switch (pattern) {
case '1U1':
posn = [];
posn.y = pal.PalletWidth / 2;
posn.angle = 0;
posn.apprDir = 0;
pallet.ProductPositions.push(posn);
break;
case '2U1':
posn = [];
posn.y = pal.PalletWidth / 2 + pal.ProductWidth / 2;
console.log('y pos 0 ' + posn.y);
pal.ProductPositions.push(posn);//first push
posn.y = pal.PalletWidth / 2 - pal.ProductWidth / 2;
console.log('y pos 1 ' + posn.y);
pallet.ProductPositions.push(posn);//first push
break;
}
}
let pal = new PalletType();
pal.PalletWidth = 1165;
pal.ProductWidth = 400
let pat = '2U1';
getPalletPositions(pal, pat);
pal.ProductPositions.forEach(function (pos) {
console.log("pos.y:" + pos.y);
});
Actual output:
y pos 0 782.5 <-value of y of first push
y pos 1 382.5 <-value of y of second push
pos.y:382.5 <-should be 782.5
pos.y:382.5
I'd expect:
y pos 0 782.5 <-value of y of first push
y pos 1 382.5 <-value of y of second push
pos.y:782.5
pos.y:382.5
I'm totally baffled and tried a few things, but to no avail.
You were mutating that object you can use spread operator or Object.assign
Check below
let ProductPosition = function (x, y) {
this.x = x;
this.y = y;
}
let PalletType = (function () {
function PalletType() {
this.PatternType = '';
this.ProductWidth = 0;
this.PalletWidth = 0;
this.ProductPositions = [];
}
});
function getPalletPositions(pallet, pattern) {
pal.ProductPositions = [];
let posn = new ProductPosition();
debugger;
switch (pattern) {
case '1U1':
posn = [];
posn.y = pal.PalletWidth / 2;
posn.angle = 0;
posn.apprDir = 0;
pallet.ProductPositions.push(posn);
break;
case '2U1':
posn = [];
posn.y = pal.PalletWidth / 2 + pal.ProductWidth / 2;
console.log('y pos 0 ' + posn.y);
pal.ProductPositions.push({...posn});//first push
posn.y = pal.PalletWidth / 2 - pal.ProductWidth / 2;
console.log('y pos 1 ' + posn.y);
pallet.ProductPositions.push({...posn});//first push
break;
}
}
let pal = new PalletType();
pal.PalletWidth = 1165;
pal.ProductWidth = 400
let pat = '2U1';
getPalletPositions(pal, pat);
pal.ProductPositions.forEach(function (pos) {
console.log("pos.y:" + pos.y);
});
That's because "posn" is an Object, so you are actually pushing a reference to this object rather than a primitive value.
You could, for example, copy the object:
pallet.ProductPositions.push({...posn});
The Spread operator will create a shallow copy.
If you need a deep copy use the following:
pallet.ProductPositions.push(JSON.Parse(JSON.Stringify(posn)));
Pay attention that the JSON method is not able to copy functions.
You're trying to push the same object 2 times in the same array. The first time with some value and next time, you're modifying the value in the same object and pushing in the array. So in total the same object reference is getting modified. As a result, the array has same object added 2 times.
Another way is, you can use slice operator on your array to create new instance of the array and then do the second push. OR create 2 different variables and then push it.
Thank you all for your prompt responses, it is very much appreciated.
Solved by using:
let x;
let y;
let angle;
let apprDir;
and assigning these directly. Then:
pallet.ProductPositions.push(new ProductPosition(x, y, angle, apprDir));
Works a treat and simplified the code.
I created two functions, GOODself and BADself, called in succession to debug a problem I have in a larger script illustrated here. I can't figure out why BADself stalls at the line aryVarAbi[0] = 5;.
If I call it first it still happens. According to the console in Firefox aryVarAbi is not defined.
GAB = GOODself(0, 4, 1);
GAB = BADself(0, 4, 1);
function GOODself(GABin, nCols, nRows) {
var aCol = 0;
var aryVarABi = [1,1,1,1];
for (aCol=0; aCol < nCols - 1; aCol++) {
alert("GOOD1 " + aryVarABi[aCol]);
aryVarABi[0]= 5;
alert("GOOD2 " + aryVarABi[aCol]);
} // for aCol
return (aryVarABi[0]);
} // GOODself
function BADself(GABin, nCols, nRows) {
var aCol = 0;
var aryVarABi = [1,1,1,1];
for (aCol=0; aCol < nCols - 1; aCol++) {
alert("BAD1 " + aryVarABi[aCol]);
aryVarAbi[0] = 5;
alert("BAD2 " + aryVarABi[aCol]);
} // for aCol
return (aryVarABi[0]);
} // BADself
JavaScript is case senstive. You've defined var aryVarABi = [1,1,1,1];. Notice the capital B. You're referring to aryVarAbi[0] = 5;. Notice the lowercase b.
I think you want aryVarABi[0] = 5; as opposed to aryVarAbi[0] = 5;
The 'b' in the latter is lowercase.
Javascript variables are case sensitive, so aryVarABi is a different variable from aryVarAbi.
Please change the line aryVarAbi[0] = 5; to aryVarABi[0] = 5;.
i was trying to implement the A* algorithm and followed the wikipedia pseudo code to make this.
when i pass a predefined object pixel to the a funtion getG() it says that the object is null. I'm sorry if i am not pointing to a specific problem but i am not even sure how to really specify the problem by name. i have tried commenting out the code to increase readability.
git repository link of the whole project - https://github.com/NirobNabil/WhirlWind
(things are a little messy here because i didn't use github at first and i uploaded it just a little ago for posting the problem)
[ i'm actually making this to use a* to find path for my bot which is powered by arduino. thats why i'm using involt. ]
here goes the code,
$(function() {
// define the height, width and bot size in centemeter
total_width = 200;
total_height = 200;
bot_size = 20;
total_box = (total_height / bot_size) * (total_width / bot_size);
box_in_x = total_width / bot_size;
box_in_y = total_height / bot_size;
//populating the pixels array
populate(total_width / bot_size, total_height / bot_size, "UND");
pathfind(pixels, pixels[13], pixels[pixels.length - 1]);
})
var pixels = []; //an array to hold all the objects(the grid)
var obstacles = []; //array to hold the obstacles
function pixel(X, Y, obs) {
this.X_co_ordinate = X;
this.Y_co_ordinate = Y;
this.state = obs; //availale states OPN, UND, OBS, DIS, NULL
this.g = 0;
this.h = 0;
this.f = 0;
this.last = null;
} //every block in the grid is a pixel
//01719372596
function populate(height, width, obs_val = "UND") {
pixels[0] = new pixel(0, 10, obs_val);
for (h = height, i = 0; h >= 0; h--) {
for (w = 0; w < width; w++, i++) {
var temp_obs = new pixel(w, h, obs_val);
temp_obs.last = pixels[0];
pixels[i] = temp_obs; //saving temp_pixel object to pixels array
}
}
} //populating the grid AKA pixels with pixel objects or blocks
// this funtion is where the problem shows up
function getG(current, start) {
let g = 1;
while (current != start && current.last != start && current) {
current = current.last;
g++;
}
return g;
} //get the g val(cost to come to this pixel from the start) of the current pixel
function getH(current, end) {
let I = Math.abs(current.X_co_ordinate - end.X_co_ordinate) + Math.abs(current.Y_co_ordinate - end.Y_co_ordinate);
return I;
} //get the h val(heuristic) of the current pixel
function getF(start, current, end) {
let G = getG(current, start);
let H = getH(current, end);
return G + H;
} //get the f val(total) of the current pixel
function lowFinArray(arr, start, end) {
// here arr is the grid/pixel
let current_low = arr[0];
for (let i = 0; i < arr.length; i++) {
let getF1 = getF(start, current_low, end);
let getF2 = getF(start, arr[i], end);
if (getF1 < getF2) {
current_low = arr[i];
}
}
console.log("current low");
console.log(current_low);
return current_low;
}
function getneighbours(grid, current) {
let neightbours = [];
neightbours.push(grid[getIndex(current.X_co_ordinate - 1, current.Y_co_ordinate)]);
neightbours.push(grid[getIndex(current.X_co_ordinate + 1, current.Y_co_ordinate)]);
neightbours.push(grid[getIndex(current.X_co_ordinate, current.Y_co_ordinate - 1)]);
neightbours.push(grid[getIndex(current.X_co_ordinate, current.Y_co_ordinate + 1)]);
/*
for(i=0; i<neightbours.length; i++){
neightbours[i].last = current;
}*/
console.log("neightbours");
console.log(neightbours);
return neightbours;
} //get the neighbour pixels of the current pixel
//main algo
function pathfind(grid, start, end) {
let closedSet = [];
let openSet = [];
openSet.push(start);
let current = start;
//trying to debug
console.log("low F in arr");
console.log(lowFinArray(grid, start, end));
console.log(start);
console.log(current);
console.log(end);
console.log(grid);
let x = 0;
while (openSet.length > 0) {
//trying to debug
console.log("executed " + (x++));
console.log("openset");
console.log(openSet);
current = lowFinArray(grid, start, end); //assigning the pixel with lowest f val to current
console.log("current");
console.log(current);
if (current == end) {
console.log(getPath(current));
}
let neighbours = getneighbours(grid, current);
for (let i = 0; i < neighbours.length; i++) {
let neighbour = neighbours[i];
if (closedSet.includes(neighbour)) {
continue;
}
if (!openSet.includes(neighbours)) {
openSet.push(neighbours);
}
//console.log(current);
let getg = getG(current, start);
let geth = getH(current, end);
//console.log(getg);
let tGscore = getg + geth; //here getH is being used as a distance funtion
if (tGscore >= getg) {
continue;
}
neighbour.last = current;
neighbour.g = tGscore;
neighbour.f = getF(neighbour);
}
if (x > 10) {
return 0;
}; //the loop was running forever so i tried this to stop the loop after 10 iterations
}
}
function getPath(current) {
let path = [current];
while (current.last != null) {
path.push(current.last);
}
return path;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
and here is what the console says,
Uncaught TypeError: Cannot read property 'last' of null
at getG (app.js:226)
at getF (app.js:241)
at lowFinArray (app.js:249)
at pathfind (app.js:292)
at HTMLDocument.<anonymous> (app.js:92)
at mightThrow (jquery-3.1.1.js:3570)
at process (jquery-3.1.1.js:3638)
You're doing your checks in the wrong order:
while (current != start && current.last != start && current) {
There's no point in using && current after you've already used current.last.
Perhaps changing the order would solve the problem. It will at least get rid of your current error:
while (current && current != start && current.last != start) {
Regarding the title of this question:
In javascript, after i pass a non null object to a funtion it says the object is null
It may very well be non-null 100% of the time you pass it into the function, but you are repeatedly overwriting its parameter within the function, so all bets are off.
I have a problem with understanding closure when I have 3 level of scopes
https://jsfiddle.net/Ar2zee/wLy8rkyL/1/
How I can get access to parameter "g" in level3 function,
var a = 10;
function level1(b) {
var c = 1;
function level2(f) {
var d = 2;
function level3(g) {
return a + b + c + d + f + g;
}
return level3()
}
return level2;
}
var temp = level1(10);
var temp2 = temp(10);
var temp3 = temp2(10);
console.log(temp3(10)); // or level(10)(); without variable
Thank you !
Line:1 invokes level1 fn and get back fn level2 stored in alias temp.
Line:2 invokes temp fn and get back fn level3 stored in alias temp2.
Line:3 now when invoking temp2 fn you execute fn level3 getting back the result of addition operation.
So temp3 is not a function but a value.
var a = 10;
function level1(b) {
var c = 1;
function level2(f) {
var d = 2;
function level3(g) {
return a + b + c + d + f + g;
}
return level3;
}
return level2;
}
var temp = level1(10);
var temp2 = temp(10);
var temp3 = temp2(10);
console.log(temp3); // or level(10)(); without variable
Just replace
Return level3()
With
Return level3
Sorry for the newb question here, but Im new to javascript. Ideally I would like to call for myLoop(latLong); but unless I make the variables outside of the function, I can't seem to have .setPosition() recognize the variable.
var x = 0;
var y = 0;
var z = 0;
var v = 0;
function xy(a,b,c,d) {
var longDistance = Math.abs(a-d);
var longTime = longDistance/0.1*0.5;
var latDistance = b-c;
var latRate = latDistance/longTime*0.5;
x = a; //origin long
y = b; //oringin lat
z = latRate;
w = d; //destination long
v = c; //destination lat
}
function myLoop () {
setTimeout(function () {
var latLong = new google.maps.LatLng(y,x);
marker.setPosition(latLong);
x = x + 0.1;
y = y - z;
if (x < w && y < v) {
myLoop();
} else {
alert('finished');
}
}, 0.5)
}
xy(-118,33,40,-73);
myLoop();
You simply need to pass the latLong variable into the myLoop() function recursively.
To do this, you can create your first latLong variable outside of the function, then call the function (passing in the first latLong variable), then within the latLong function, check for your conditions, and if you need to call the myLoop function again, update the latLong variable and then call the myLoop function again.
Here is what your recursive code would look like:
var x = 0;
var y = 0;
var z = 0;
var v = 0;
// Your first latLong
var latLong = new google.maps.LatLng(y,x);
function xy(a,b,c,d) {
// ...
}
// Pass in the latLong variable
function myLoop (latLong) {
setTimeout(function () {
marker.setPosition(latLong);
x = x + 0.1;
y = y - z;
if (x < w && y < v) {
// now create a new latLong, and pass it
// back into this function recursively
latLong = new google.maps.LatLng(y,x);
myLoop(latLong);
} else {
alert('finished');
}
}, 0.5)
}
xy(-118,33,40,-73);
// Now call the myLoop function to get the recursion started
myLoop(latLong);
Alternatively, you can wrap all the code up into one function
Using the revealing module pattern, you can wrap up all your loop functionality in one place (within a function object called latLongGenerator), allowing for a nice separation in your code logic, but still giving you a clean interface to use. The restructured "revealing module" code would look like this:
var latLongGenerator = (function () {
var x = 0;
var y = 0;
var z = 0;
var v = 0;
var latLong;
function setXY(a,b,c,d) {
var longDistance = Math.abs(a-d);
var longTime = longDistance/0.1*0.5;
var latDistance = b-c;
var latRate = latDistance/longTime*0.5;
x = a; //origin long
y = b; //oringin lat
z = latRate;
w = d; //destination long
v = c; //destination lat
// pass in the initial latLong to myLoop(latLong) from here
latLong = new google.maps.LatLng(y,x);
myLoop(latLong);
}
// This is the only function that will
// be exposed publicly on this function
// Example usage: latLongGenerator.startLoopWith(0,0,0,0);
function startLoopWith(a,b,c,d){
setXY(a,b,c,d);
}
function myLoop (latLong) {
setTimeout(function () {
marker.setPosition(latLong);
x = x + 0.1;
y = y - z;
if (x < w && y < v) {
// recursively call the loop from here
latLong = new google.maps.LatLng(y,x);
myLoop(latLong);
} else {
alert('finished');
}
}, 0.5);
}
return {
startLoopWith:startLoopWith
};
})();
// Finally, you can start your loop by passing in
// your initial values to latLongGenerator.startLoopWith(...)
latLongGenerator.startLoopWith(-118,33,40,-73);
This structure gives you a clean way of encapsulating all your calculation logic, while also giving you a nice, clean entry point. Using this new refactor, you can get your loop started with one line:
latLongGenerator.startLoopWith(-118,33,40,-73);
I haven't tested this code, but it should help you get on the right track.
Hope this helps!