I am learning Javascript for a project using online resources however i don't know how to get this function working.
var results =[[a1,a2,a3,a4,a5]];
var winner = 0;
function checkWinner (results)
{
for (var i = 0; i < results.length; i++)
if (results[0][i] > 50)
{
winner = results[0][i];
}
}
Just after the function, i use:
checkWinner(results);
In a HTML file i use alert to display the variable winner. But it obviously doesn't work. I realise it is a problem with my understanding of scope and global variables.
should be
var Results =[[a1,a2,a3,a4,a5]];
var winner = 0;
function checkWinner (results)
{
for (var i = 0; i < results[0].length; i++)
if (results[0][i] > 50)
{
winner = results[0][i];
}
}
checkWinner(Results);
To avoid name collisions name global variables from capital case.
Also in your code you call the length of the "parent" array. You need to specify the length of the "Child" array
You've got to understand the concept of scope. The variables results and winner are not the same inside and outside the function.
Also, you've got to call the function and return something from it if you want to change the value of the variables outside the function (unless you use globals). This seems to be hard for novice programmers to understand, but merely defining a function doesn't do anything.
var results =[[a1,a2,a3,a4,a5]];
function checkWinner (results)
{
for (var result in results[0])
{
if (result > 50)
{
return result;
}
}
}
var winner = checkWinner(results);
Note that:
I used a for each loop, which has a cleaner syntax.
I am also iterating over results[0] instead of results, since you've got a nested array for whatever reason.
Because your function has an argument called results, it requires you to pass the global results in spite of it being a global. Another way to do this:
var results = [[a1,a2,a3,a4,a5]];
function checkWinner()
{
for (var result in results[0])
{
if (result > 50)
{
winner = result;
return;
}
}
}
checkWinner();
However, I would recommend against using global variables this way. Here's an explanation on why global variables are bad. It's for C++, but it applies to JavaScript as well.
You're iterating over the result[0] array (the array in result[0]), but using the length of the result array.
Related
I am triying to create a constructor function in order to aferwards be able to instance it to create game boards objects. The program is simple, I just passed the constructor the number of rows and it has to create them.
The for loop is not working and I dont understand the reason, ySize variable is defined. If I remove the for the program works sucessfully and create the section with no problem. Which is the problem with the for loop?
Thank you very much for your time
function AlgorithmType(ySize) {
this.ySize = ySize;
this.createBoard = function() {
let selector; let row
for(let i = 0; i ++; i <= this.ySize) {
debugger; // Debugger is not executed
selector = document.querySelector(".mainContainer")
row = document.createElement("section")
selector.appendChild(row)
}
}
}
let testBoard = new AlgorithmType(5)
testBoard.createBoard() //expected to create 5 rows
Your function rebinds this, which is why this.ySize is not defined. Use an arrow function to access this of the lexical scope (parent scope):
function AlgorithmType(ySize) {
this.ySize = ySize;
this.createBoard = () => {
let selector; let row
for(let i = 0; i <= this.ySize; i++) {
debugger; // Debugger is not executed
selector = document.querySelector(".mainContainer")
row = document.createElement("section")
selector.appendChild(row)
}
}
}
Side note: As #atomNULL pointed out, your for-loop syntax is incorrect as well. See his answer
Your for loop syntax is wrong, the correct syntax would be:
for (let i = 0; i <= this.ySize; i++)
Also you should use an arrow function to access this instead of rebinding it current way.
This question has been flagged as already answered with a link provided above. However, I already read that answer and it only answered how to use setInterval in a for loop. There were no functions being called with parameters passed to them in that solution, and that is my situation, so I couldn't use it to fix my situation.
I'm fairly new to programming, so I'll try to describe as best as I can. In setInterval, I am passing a parameter to the function toggleClusters which setInterval calls. The debugger shows the parameter as being correct. It is a reference to an array position that holds an object literal that contains map marker objects. I seem to be misunderstanding something about what values stay around and what do not when using setInterval, because the debugger shows the correct object literal being passed as an arg, but when the function is called, the debugger shows the obj that is supposed to be passed as undefined. Is it that this passed value no longer exists when the function is called?
function setClusterAnimations() {
for (var i = 0; i < clusters.length; i++) {
//intervalNames stores handle references for stopping any setInterval instances created
intervalNames.push(setInterval(function () {
//clusters[i] will hold an object literal containing marker objects
toggleClusters(clusters[i]);
}, 1000));
}
}
//cObj is coming back as undefined in debugger and bombing
function toggleClusters(cObj) {
var propCount = Object.keys(cObj).length;
for (var prop in cObj){
if (prop.getZIndex() < 200 || prop.getZIndex() == 200 + propCount) {
prop.setZIndex(200);
}
else {
prop.setZindex(prop.getZIndex() + 1)
}
}
}
This is typically the issue with such asynchronous calls as with setInterval(). You can solve this in different ways, one of which is using bind():
for (var i = 0; i < clusters.length; i++) {
//intervalNames stores handle references for stopping any setInterval instances created
intervalNames.push(setInterval(function (i) {
//clusters[i] will hold an object literal containing marker objects
toggleClusters(clusters[i]);
}.bind(null, i), 1000));
}
The toggleClusters(clusters[i]) statement will only be executed when your loop has finished, at which time i will be beyond the correct range (it will be clusters.length). With bind(), and mostly with the function parameter i, you create a separate variable in the scope of the call back function, which gets its value defined at the moment you execute bind(). That i is independent from the original i, and retains the value you have given it via bind().
that is because your "i" variable is not captured in the function passed as an argument to setInverval.
Therefore , when this function is invoked, i is always equal to clusters.length.
consider the differences between the two following pieces of code:
var arr = [1, 2, 3];
var broken = function() {
for(var i = 0; i < arr.length; ++i) {
setInterval(function() {
console.log("broken: " + arr[i]);
}, 1000);
// logs broken: undefined
}
};
var fixed = function() {
for(var i = 0; i < arr.length; ++i) {
setInterval((function(k) {
return function() {
console.log("fixed: " + arr[k]);
}
}(i)), 1000); // i is captured here
}
};
I don't have much JavaScript experience. My question is this:
When I'm writing a JavaScript library, and many of the functions I'm writing functions are meant to call each other and users can call the functions I'm defining on each other in ways I might not have predicted but are valid, how do I keep the iterators in functions that have iterating loops straight?
Do I have to come up with new names for each iterator in a for loop every time I do a for-loop just to be safe that I haven't accidentally used the same variable in two functions where one function might nest inside the other in a situation I haven't predicted or thought of?
These are just a couple examples of functions that have iteration in them. Everything I'm writing is for working with interacting with Qualtrics surveys (shown in gif examples below).
function watchSet(set, mathFunction) {
var setSize = set.length;
for (var i=0; i < setSize; i++) {
set[i].down().observe("keyup", mathFunction );
}
}
function mathSum(set, output) {
var setTotal = 0;
for (var j=0; j < (set.length); j++) {
var setInputValue = parseInt(set[j].down().value, 10);
if (isNaN(setInputValue)) { setInputValue = 0; }
setTotal = setTotal + setInputValue;
}
output.value = setTotal;
}
function validateError(array, color) {
if (color === undefined) {
color = "pink";
}
color = color.concat(";");
for (var k=0; k < array.length; k++) {
array[k].down().setAttribute("style", "background-color: ".concat(color));
}
$('NextButton') && $('NextButton').hide();
}
function cellRange(startCell, endCell) {
var r1 = /^[A-Z]/;
var r2 = /[0-9]{1,3}$/;
var startCellColumn = r1.exec(startCell)[0].charCodeAt(0) - 61;
var endCellColumn = r1.exec(endCell)[0].charCodeAt(0) - 61;
var startCellRow = parseInt(r2.exec(startCell)[0], 10);
var endCellRow = parseInt(r2.exec(endCell)[0], 10);
var tempRange = [];
for (var q=startCellColumn; q<=endCellColumn; q++) {
for (var r=startCellRow; r<=endCellRow; r++) {
tempRange.push(q);
tempRange.push(r);
}
}
var outputRange = [];
for (var s=0; s < tempRange.length; s+=2) {
outputRange.push(cell(String.fromCharCode(tempRange[s]+61).concat(tempRange[s+1])));
}
return outputRange;
}
Gif Examples:
setting equivalency-validation
summing a couple cells
No, you don't need unique variable names in different functions.
Variables declared with var are local to the function scope in which they are declared in. They will not and do not conflict with anything outside that scope. So, your three functions watchSet(), mathSum() and validateError() can all use var i just fine and will not conflict with each other or with any third party code outside of those functions. Local variables like this are created uniquely each time the function is run and can be referred to only from within that function.
If you did not use var to explicitly declare your loop variables, then Javascript would "implicitly" create global variables by that name and then, yes, your different functions could collide if one function doing this called another so thus they were both trying to use the same global at the same time. But, as long as your variables are declared with var and your code is in a function (thus not running at the global scope), this will not happen.
You can also run your code in strict mode (highly recommended) because then an accidential implicit global is an immediate error and the interpreter will immediately show you where the problem is.
Or use .forEach()
You can also use .forEach() on arrays and not have to create your own iteration index at all.
function watchSet(set, mathFunction) {
set.forEach(function(item) {
item.down().observe("keyup", mathFunction );
});
}
Or, use let in an ES6 environment
In an ES6 environment, you can use let instead of var and the variable will be scoped to only the for loop too.
function watchSet(set, mathFunction) {
var setSize = set.length;
// when declaring with let in a for loop, the variable is scoped to
// only inside the for loop
for (let i=0; i < setSize; i++) {
set[i].down().observe("keyup", mathFunction );
}
// with let in a for declaration, even another use in the same function
// does not conflict
// this is a completely different variable than the one above
for (let i=0; i < setSize; i++) {
set[i].up().observe("keyup", mathFunction );
}
}
I have seen many examples where people have nested for loops and they change their increment variable (i,j,k).
for(var i=0;i<array.length;i++){
for(var j=0;j<array.length;j++){
for(var k=0;k<array.length;k++){
}
}
}
So my question is why doesn't calling a function from a for loop, that has a for loop inside it not cause a collision of the increment variables? Is it because of the function scope nature of javascript or is it colliding and I just haven't had a problem. Example:
for(var i=0;i<array.length;i++){
callFunction()
}
function callFunction(){
for(var i=0;i<arry.length;i++){
console.log(i)
}
}
I don't know why adeneo didn't make it an answer, but indeed it has to do with scope. Compare it to:
function first() {
var i = 2;
console.log(i);
}
function second() {
var i = 3;
console.log(i);
first();
}
The i variable in each function is contained within the function, so the variables don't clash. If you had used global variables (i = 3 instead of var i = 3) then they would've clashed.
If you want some material on javascript and scope rules, check out this question or these links:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope
http://coding.smashingmagazine.com/2009/08/01/what-you-need-to-know-about-javascript-scope/
I am using a getJSON method to post the data I have in a database, through a for loop and into an HTML page. But I would like to the function to call different tables in my database depending on the integer the for loop is currently on, something like this:
for (var r = 0; r < 8; r++){
$.getJSON("PHP-PAGE.php?jsoncallback=?", function(table+r) {
//function stuff here
});
}
But when I try to do this, the "table+r" is flagging a syntax error. What am I doing wrong?
You are defining a function, not calling it. Between ( and ) you have to put identifiers (variable names) not expressions.
To pass data here, you need to use variables from a wider scope than the function. Since the variable is going to change (and the function is called asynchronously) you have to use a closure to do this.
function mkCallback(table) {
var foo = "table" + table;
return function () {
// function stuff that uses foo here
// foo from the time mkCallback was called to make this function
// will still be in scope
};
}
for (var r = 0; r < 8; r++){
$.getJSON("PHP-PAGE.php?jsoncallback=?", mkCallback(table+r));
}
function(table+r) { tries to create a function with table+r as a parameter, but + is not valid in a variable name. I think you instead want something like this:
for (var r = 0; r < 8; r++){
$.getJSON("PHP-PAGE.php?jsoncallback=?",
(function(currentR){
return function() {
var someVariable=table+currentR; // No idea where table came from...
//function stuff here
}
})(r));
}
As #Quentin mentioned by the time the callback is called, r will have reached its final value, hence the interesting closure.
I think what you probably want is
for (var r = 0; r < 8; r++){ //outer loop
function(tablenum){ //closure function
tablename = table+tablenum // saved reference to "table+r"
$.getJSON("PHP-PAGE.php?jsoncallback=?", function() {
//function stuff here, using tablename as the param
});
}(r)
}
This creates a closure to maintain the value of the iterated value. You can reference tablename in the callback function, and that will refer to a value equivalent to table+r
The issues with your original example
You were putting table+r as a parameter to a function you were defining, rather than an argument to one you were calling
You were trying to get the callback to reference r. But the callback won't run until after the loop has executed, so r will be 8 for all callback functions.
If you were trying to reference "table1", "table2" then you want to have "table"+r. Otherwise I assume you're referencing a table variable outside the scope of the code you showed us.
You can directly reference the variable r in your callback. Not sure what table is - the return data from the JSON call? Try the following:
for (var r = 0; r < 8; r++){
$.getJSON("PHP-PAGE.php?jsoncallback=?", function(jsonReturnData) {
//function stuff here
alert(r);
});
}