Javascript giving parameters to inner function - javascript

So my basic setup is this:
for (var i = 0; i < 3; i++) {
var indices = [-1, -1, -1];
while (index == -1) {
// Do Stuff
index[i] = newIndex;
}
var press = function() { alert(i); };
new control({press: press});
}
Now when I press the each of the new controls instead of getting alert(0), alert(1) and alert(2) I get alert(3), alert(3) and alert(3).
I can kind of understand whats going on. Now my question: how can i pass the different indexes to the function as I intended?

It is because closure variable i, the solution is to create a private closure for each loop.
for (var i = 0; i < 3; i++) {
var indices = [-1, -1, -1];
while (index == -1) {
// Do Stuff
index[i] = newIndex;
}
var press = (function(myvar){
return function() { alert(myvar); };
})(i);
new control({press: press});
}

Use closure:
var press = (function (x) {
return function () {
alert(x);
};
})(i);
This way the current i value is saved in a safe place, a private function.
Note that declaring variables (with var) inside loops are not standard, you should declare the press variable outside the loop.

Related

Programmatically setting third statement of for loop

Wondering if there is by any chance to programmatically setting third statement of forloop
var conditionProgrammatically = 'i++';//or 'x--'
for (var i = 0; i < 10; conditionProgrammatically) {
console.log(i)
}
You can use any expression you want there including calling a function. You just need to be careful of scope. So, for example, this works:
var conditionProgramatically = () => i++ ;
for (var i = 0; i < 10; conditionProgramatically()) {
console.log(i)
}
But it depends on the fact that var i is in a scope shared by the function. This, however, doesn't work:
var conditionProgramatically = () => i++ ;
for (let i = 0; i < 10; conditionProgramatically()) {
console.log(i)
}
Because let is scoped to the block and not available.
Of course you can share an object which is mutable by passing it as an argument like:
fn = (o) => o.i += 1
for (let o = {i:0}; o.i < 10; fn(o)) {
console.log(o.i)
}
This allows you to use let, but is a little hard on the eyes.
All said, it's probably going to be easier to make your logic fit in a simple expression rather than calling a function. You can still perform some logic, though:
for (let i = 0; Math.abs(i) < 10; i = Math.random() > .65 ? i -1: i + 1) {
console.log(i)
}
You can set a variable and then operate with this variable according to your needs.
(remember that i-- is equivalent to i -= 1).
BTW, be careful because you would also have to change the condition, if not you will end up in an infinite loop. In your case, I would use abs()
var step = 1; // or var step = -1;
for (var i = 0; abs(i) < 10; i += step) {
console.log(i)
}
Usually, in functional programmings (like python and javascript), we can use dictionary (or objects) to store functions.
var myFunctions = {
"a": function (i) { return i + 1 },
"b": function (i) { return i - 3 }
};
Then, we can set the condition as the key to the dictionary:
myCondition = "a"; // this will set condition to increment by 1
Here is your for loop:
for (i = 0; i < n; i = myFunctions[myCondition](i)) {
// whatever
}

use apply() to execute array of setTimeouts with args

I need to be able to build an array of anonymous functions that execute setTimeout with unique arguments per function. The following code has already been proposed, and works, on SO, but it only deals with immediate execution of the setTimeout. It does not explain how one can accumulate a collection of setTimeout functions to an array, with each setTimeout function having its own closure that defines a unique variable to be used in the execution of the setTimeout.
This is what exists already on SO:
var strings = [ "hello", "world" ];
for(var i=0;i<strings.length;i++) {
setTimeout(
(function(s) {
return function() {
alert(s);
}
})(strings[i]), 1000);
}
This is one of many permutations of what I have tried:
var strings = [ "hello", "world" ];
var func_array = [];
for (var i=0; i < strings.length; i++) {
func_array.push(function() {
setTimeout(
(function(s) {
return function() {
alert(s);
}
})(strings[i]), 1000);
});
}
When apply() is called on func_array, the strings[i] value is the same for each call, i.e. the final member of the strings array.
Another attempt: here we make the function that gets pushed onto func_array self-executing in order to scope the strings[i] variable correctly. However, apply() sees only 'undefined' since the function has already executed.
var strings = [ "hello", "world" ];
var func_array = [];
for (var i=0; i < strings.length; i++) {
func_array.push(function(s) {
setTimeout(
(function(s) {
return function() {
alert(s);
}
})(s), 1000);
}(strings[i]));
}
Ideas?
Use Function.prototype.bind(). It becomes much simpler than it actually is.
var strings = [ "hello", "world" ];
var func_array = [];
for (var i=0; i < strings.length; i++) {
var fn = function(string){
return setTimeout(function(){ alert(string) } ,1000);
};
func_array.push(fn.bind(this, strings[i]));
}
This does what you want.
var strings = ["hello", "world"];
var func_array = [];
for (var i = 0; i < strings.length; i++) {
(function (s) {
var func = function () {
alert("String is " + s);
}
var futureFunc = function () {
setTimeout(func, 1000);
}
func_array.push(futureFunc);
} (strings[i]));
}
func_array[0]()
func_array[1]()

Javascript - Variable updating

This is probably an easy question but it's late at night and I can't get my head round this.
here's my code
$(document).ready(function () {
var items = getNumber();
for (var i = 0; i < items.length; i++) {
var test = items[i].action;
test();
}
});
function getNumber()
{
var items = [];
for (var i = 0; i < 5; i++) {
var num = i * 10;
items.push({ id: i, number: num, action: function () { alert(i) } });
}
return items
}
Could someone explain to me why the alert output is always 5? I want the alert parameter to be the index at the time it is added to the array. It seems like it is being dynamic.
If you could also post a solution how i could get this to work i would be extremely thankful
This is a common issue with JavaScript variable scoping: new variables are only introduced in a new execution context and thus, in the problematic code, i is shared across all the action callbacks.
Anyway, here is the corrected code following the standard idiom:
function getNumber()
{
var items = [];
for (var i = 0; i < 5; i++) {
var num = i * 10;
items.push({
id: i, number: num,
// _i is a new variable for each callback
action: (function (_i) {
// use separate (one per callback) _i variable
return function () { alert(_i) }
})(i) // pass in current value for loop
});
}
return items
}
Alternatively, if one doesn't like all the nesting, it's fine to use a "named" function to perform the same task. The key to point is that the closure is created (and returned from) a new execution context so that a different variable is closed-over:
function getNumber()
{
function mkAction (i) {
return function () { alert(i) }
}
var items = [];
for (var i = 0; i < 5; i++) {
var num = i * 10;
items.push({
id: i, number: num,
action: mkAction(i)
});
}
return items
}
Another approach is to use Function.bind from ES5:
function getNumber()
{
var items = [];
for (var i = 0; i < 5; i++) {
var num = i * 10;
items.push({
id: i, number: num,
action: (function (_i) { alert(_i) }).bind(null, i)
});
}
return items
}
(Note that Function.bind can be emulated using a new execution context/closure even without native browser support. See the MDC documentation.)
See also:
JavaScript closure inside loops – simple practical example
Passing functions to setTimeout in a loop: always the last value?
How do JavaScript closures work?

Closures in Javascript: assigning local variable doesn't work

Just when I thought I understood closures...
The following code snippet:
function f() {
var a = [];
var i;
for (i = 0; i < 3; i++) {
a[i] = function () {
var x = i;
return x;
}
}
return a;
}
var a = f();
console.log(a[0]());
console.log(a[1]());
console.log(a[2]());
prints out 3, 3, 3. I don't understand why. I'm copying the value of 'i' to the local variable x, so there should be three x's: x0=0, x1=1. x2=2. How are all of them reading the final value of i?
Your problem is caused by each a[i] being, in fact, a closure. They all share the same i, which is evaluated when each a[i] is called, not when the loop executes. You need to create each closure with a separate context. For instance:
function f() {
var a = [];
var i;
for (i = 0; i < 3; i++) {
a[i] = makeClosure(i);
}
return a;
}
function makeClosure(i) {
return function () {
var x = i;
return x;
}
}
Even though the value of i changes in your for loop, it's still the same i variable. You need to shadow i in that scope and effectively pass it by value:
for (var i = 0; i < 3; i++) {
(function(x) {
a[x] = function() {
return x;
}
})(i);
}

Is there a better way to write these functions?

I'm not a javascript programmer by any means, but this has been annoying me for the longest while,
is there a better way to write these two seperate functions.
As in a single function?
function showAll()
{
var collection = getElementsByClassName("dealHolder");
for (var x = 0; x < collection.length; x++)
{
setParentTrue(collection[x].parentNode);
}
}
function setParentTrue(obj) {
if (obj.id != "deal")
{
obj.id = "true";
setParentTrue(obj.parentNode);
}
else
{
obj.style.display = 'block';
}
}
Can I declare a function within another and recursively call it? any time I need to recurse I always seem to be creating a separate function specifically for it
Cheers for the advice
function showAll()
{
var collection = getElementsByClassName("dealHolder"),
x = 0,
setParentTrue = function(obj) {
if (obj.id != "deal")
{
obj.id = "true";
setParentTrue(obj.parentNode);
}
else
{
obj.style.display = 'block';
}
};
for (x = 0; x < collection.length; x++)
{
setParentTrue(collection[x].parentNode);
}
}
Yes, you can declare a function within a function, as functions are objects.
function showAll()
{
var setParentTrue = function (obj) {
if (obj.id != "deal")
{
obj.id = "true";
setParentTrue(obj.parentNode);
}
else
{
obj.style.display = 'block';
}
}
var collection = getElementsByClassName("dealHolder");
for (var x = 0; x < collection.length; x++)
{
setParentTrue(collection[x].parentNode);
}
}
Actually - writing a separate function to hold what occurs within a loop is good practise so I would not change what you have above.
Actually - no I take that back - in this case the function within the loop is unlikely to be usable to anyone else, so I'd go for one of the examples below. Nested within the same object, but still separate function.

Categories

Resources