Say I have a hundred functions and a hundred HTML buttons and I want to assign them all to their click events.
I could name them like button1, button2, button3, ... and function1, function2, function3 ...
Then say:
let btsn = document.getElementsByClassName("mybuttons");
for (int i = 0; i < 100; i++) {
btns[i].addEventListener("click", "function" + i);
}
Of course this doesn't work because a string literal doesn't get translated into an actual reference to the function, it's just me stating its name randomly and gets forgotten.
But is there some way I could achieve this as though that were possible?
edit:
The exact functionality I was looking for can be done by putting the functions in an array.
let funcs = [
function a() { ; }
function b() { ; }
function c() { ; }
function d() { ; }
function e() { ; }
]
let btsn = document.getElementsByClassName("mybuttons");
for (int i = 0; i < 100; i++) {
btns[i].addEventListener("click", funcs[i]);
}
Related
I had a class in my code and I declared a constructor inside it...
constructor(rowNumber) {
this._rows = this.init(rowNumber);
}
get lastRow() {
return this._rows[this._rows.length - 1];
}
get rows() {
return this._rows;
}
fact(n) {
return (n > 1) ? this.fact(n - 1) * n : 1;
}
createRow(row) {
var result = [];
for (let i = 0; i <= row; i++) {
result.push(this.fact(row) / this.fact(i) / this.fact(row - i));
}
return result;
}
init(rowNumber) {
var result = [];
for (let i = 0; i < rowNumber; i++) {
result.push(this.createRow(i));
}
return result;
}
}
export {Triangle};
I declared init() function at the end of my code and I used init() in the constructor... if the constructor runs at first and then init() function runs ... does it cause a problem?
Javascript is first creating a class. That'll be an object which contains all those functions on its prototype. You then sometime later instantiate that class with new, at which point constructor and init will be called. At that point it doesn't matter in which order they were written into the source code, since they've already been parsed and put onto the prototype from where they will be called.
JSHint shows the error:
"Function declared within loop referencing an outer scope variable may lead to confusing semantics".
How can I improve the following code to get rid of the warning?
var getPrecedence = function getPrecedence(operator, operators) {
var keys = Object.keys(Object(operators));
for (var i = 0, len = keys.length; i < len; i++) {
var check = Object.keys(operators[keys[i]]).some(function (item) {
return item === operator;
});
if (check) return operators[keys[i]][operator];
}
};
You are supposed not to use the function expression inside the loop body, but instead declare it outside:
function getPrecedence(operator, operators) {
function isOperator(item) {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
return item === operator;
}
var keys = Object.keys(Object(operators));
for (var i = 0, len = keys.length; i < len; i++) {
var check = Object.keys(operators[keys[i]]).some(isOperator);
// ^^^^^^^^^^
if (check) return operators[keys[i]][operator];
}
}
Of course the whole thing could be simplified by just using includes instead of some, and find instead of the loop:
function getPrecedence(operator, operators) {
var keys = Object.keys(Object(operators));
var opkey = keys.find(key =>
Object.keys(operators[key]).includes(operator)
);
if (opkey) return operators[opkey][operator];
}
And finally, Object.keys(…).includes(…) can be simplified to operator in operators[key].
Add it before calling the function, this one will bypass that check
/* jshint -W083 */
window.TicTacToet.compMove = function (row, col) {
var player = window.TicTacToet.PlayerTurn;
var board = window.TicTacToet.Board;
for (i = 0; i < window.TicTacToet.Board.length; i++) {
for (j = 0; j < window.TicTacToet.Board[i].length; j++) {
if (window.TicTacToet.Board[i][j] == null) {
getWin(row, col, player, board);
} else {
console.log("position occupied");
}
}
}
}
function getWin($r, $c, $player, $board) {
checkTop($r, $c, $player, $board);
}
function checkTop($x, $y, $player, b) {
console.log("ENTER");
var success = false;
for (i = 0; i < 3; i++) {
$x--;
if ($x < 0) {
return success;
}
if (b[$y][$x] != $player) {
return success;
}
}
success = true;
return success;
}
The function check-Top is executing infinite times. The parameters row and col are co-ordinates of the table. Player will return true or false and the board is an array having 9 elements. Both window.TicTacToet.Board.length and window.TicTacToet.Board[i].length have value 9 , i.e 9 x 9 .The console.log("ENTER") should execute 91 times but it is executing infinite times.what may be the reason for this. Because of this all other functions are not working properly, game itself not playing.Please Help out. This is for 9 x 9 clickable board drawing game.
I guess you might want to use var keyword for variable i,
because you are using same variable name i at two for loops. So, at the second for loop, you are unintentionally overwriting i of the first for loop. To avoid this, you can declare variables with var keyword, which defines variable scope.
Change
for(i=0;i<window.TicTacToet.Board.length;i++)
To
for(var i=0;i<window.TicTacToet.Board.length;i++)
And Change
for (i=0;i<3;i++)
To
for (var i=0;i<3;i++)
JavaScript has function-level scope. When you declare variables within a function, they are only accessible within that function. The code below explains how variable scope works in JavaScript:
Without var keyword.
i = 100;
function foo(){
i = 0; // overwriting i to 0
}
foo();
alert(i); // shows 0
With var keyword.
var i = 100;
function foo(){
var i = 0; // This defines a new variable 'i' in the scope of function foo(){}.
}
foo();
alert(i); // shows 100
With var keyword ( in nested functions )
var i = 100;
function foo(){
var i = 200; // A new variable 'i' in the scope of function foo(){}.
function bar(){
var i = 0;// A new variable 'i' in the scope of function bar(){}.
}
bar();
alert(i); // shows 200
}
foo();
alert(i); //shows 100
In most languages which have block-level variable scope, variable are accessible whithin their block surrounded by curly brackets ({and}). But JavaSciprt doesn't terminate scopes at the end of blocks, but terminate them at the end of functions.
I'm sure there are many articles and documents about it. I googled it and found an intresting introductory article.
http://javascriptissexy.com/javascript-variable-scope-and-hoisting-explained/
Hope this helps.
I have a question to a specific behavior of javascript:
I have an object which I want to fill with generated functions. Each function contains a variable which is changed during the loop of function generation.
My problem is that the variable does not get replaced when assigning the function to the object. Instead the reference to the variable stays in the function and when executing the function only the last value of the variable is remembered.
Here is a minimal example (also on jsfiddle: http://jsfiddle.net/2FN6K/):
var obj = {};
for (var i = 0; i < 10; i++){
var nr = i;
obj[i] = function(){
console.log("result: " + nr);
}
}
for (var x = 0; x < 10; x++){
obj[x]();
}
The second loop executes all generated functions and all print a 9 as result. But i want that they print the value which the variable had at the time of generation (0, 1, 2, ...).
Is there a way to do this? Thanks in advance.
One approach is to call a function that returns a function:
function makeFunc(i) {
return function() {
console.log("result: " + i);
}
}
for (...) {
obj[i] = makeFunc(i);
}
Another approach is the immediately invoked function expression:
for (i = 0; ...; ...) {
(function(i) {
obj[i] = function() {
console.log("result: " + i);
}
})(i);
}
where in the latter case the (function(i) ... )(i) results in a permanent binding of i passed as a parameter to the outer function within the scope of the inner function
The problem is that all the functions you create are sharing a reference to the same nr variable. When you call them they fetch the value using that reference and therefore all of them get the same result.
Solve it like this:
for (var i = 0; i < 10; i++){
(function(nr) {
obj[nr] = function(){
console.log("result: " + nr);
}
})(i);
}
Your surmise is correct, and yes, there's a solution:
obj[i] = function( nr_copy ) {
return function() {
console.log("result: " + nr_copy);
};
}( nr );
JavaScript variables are scoped at the function level, unlike some other block-structured languages. That is, the fact that you declare "nr" inside the for loop doesn't make it "local" to that block — the effect is precisely the same as if you'd declared it at the top of the function.
By introducing another function scope with that anonymous function, you make a new copy of the value of "nr", which is then privately accessible to the actual function that's returned. Each of those functions will have it's own copy of the value of "nr" as it stood when that slot of the "obj" array was initialized.
what you want is to create a closure for every function you create.
Yet, the var(s) have not a block scope, so your code is the same as :
var obj = {};
var i;
var nr;
for (i = 0; i < 10; i++){
nr = i;
obj[i] = function(){
console.log("result: " + nr);
}
}
which hopefully makes it more obvious all functions will refer to the very same 'nr' var.
What you want to do implies creating a new scope each time, which might be done using bind, but let's stick to your original intent and build a new closure each time with a lambda :
var obj = {};
for (var i = 0; i < 10; i++) {
obj[i] = (function(){
var this_nr = i;
return function(){
console.log("result: " + this_nr);
}
}() );
}
I want to pause 1 second for every time it loops, it is usually easy to do similar pauses on other cases, but when working with loops, it seems it get harder:
for (var i=0 ; i < 10 ; i++) {
document.write (i + "<br>");
// I want to wait 1 second here
}
This is one example of my thousands failed attempts:
function writeMsg (index) {
document.write (index + "<br>");
}
for (var i=0 ; i < 10 ; i++) {
setTimeout (writeMsg(i), 1000);
}
Any ideas of how to get this to work?
This function works more like a normal for loop while it isn't
You need to take into account that a for gets 3 arguments inbetween semicolons.
Before starting (ie var i=0 you define a variable)
A condition before running the code again (ie i < 10 while i is under 10)
An action everytime it finishes the code again (i++ add one to i)
Code
(function() {
// Define a variable
var i = 0,
action = function() {
// Condition to run again
if (i < 10) {
document.write(i + "<br>");
// Add one to i
i++;
setTimeout(action, 1000);
}
};
setTimeout(action, 1000);
})();
Here is a jsfiddle for this code demonstrating its working:
http://jsfiddle.net/sg3s/n9BNQ/
You pass the return value of a function call to setTimeout instead of a function. Try the following code:
for (var i = 0; i < 10; i++) {
(function(i) {
setTimeout(function() {
writeMsg(i);
}, 1000*i);
})(i);
}
In case you wonder why the call is wrapped inside an anonymous function: Without that function each setTimeout callback would receive the same i so when the callbacks fire it would always be 10. The anonymous function creates a new i inside that is not connected to the loop variable.
Classic function-in-a-loop problem. One archetypal solution:
function createCallback(i) {
return function () {
writeMsg(i);
};
}
function writeMsg (index) {
document.write (index + "<br>");
}
for (var i=0 ; i < 10 ; i++) {
setTimeout (createCallback(i), 1000*i);
}
The 10 timeouts are all based on the time that setTimeout() is called. So, they are all triggered at the same time.
for (var i=0; i < 10; i++) {
(function(idx){
setTimeout(function(){
document.write(idx+"<br/>");
},1000*idx);
})(i);
};
try this it will definitely help who all are think how to make it work wait property inside For Loop...
try this code in this URL http://www.shopjustice.com/the-collections/C-10329.
var var2;
var tmp;
var evt;
var i=0;
var res = document.getElementsByClassName('mar-plp-filter-content nav nav--stacked')[0].children.length;
tmp = document.getElementsByClassName('mar-plp-filter-content nav nav--stacked')[0].children;
function myfunc()
{
if(i<res)
{
var2 = tmp[i].getElementsByTagName("span")[0].getElementsByClassName("inverted")[0];
// alert(var2.innerHTML);
var evObj = document.createEvent('MouseEvents');
evObj.initEvent( 'mouseover', true, false );
var2.dispatchEvent(evObj);
var2.style.backgroundColor="GREEN";
i++;
setTimeout(myfunc,3000);
}
};
setTimeout(myfunc,3000);