Closure for setInterval function in javascript - javascript

How to use setInterval without using global variables? I'd prefer to wrap all variables of function invoked by setInerval in some kind of closure, like so:
var wrap = function (f){
var local1, local2, ...;
return function () { return f(); }
}
This doesn't work, but the idea is that I'd pass wrap(f) instead of f to setInterval, so that locals for f are nicely wrapped and don't pollute the global scope.

javascript don't have dynamic binding.(except this keyword)
use anonymous function can archive your idea. (it called closure)
var fnc = function(){
var local1, local2;
return function(){
// using local1, local2
}
};
setInterval(fnc, 1000);

I assume you're looking for something like this...
var wrap = function (f){
var locals = Array.prototype.slice.call(arguments, 1);
return function () { f.apply(this, locals); }
};
function logger_func() {
console.log.apply(console, arguments);
}
for (var i = 0; i < 10; i++) {
setTimeout( wrap(logger_func, i, "foo_" + i), // <-- wrapping i
i * 1000 );
}
Note that modern environments let you pass extra arguments to setTimeout...
for (var i = 0; i < 10; i++) {
setTimeout(logger_func, i * 1000, i, "foo_" + i);
}

Related

How to make the return variable hold a new value after Increment/Decrementing it in a function?

Everytime I run this function, the p1_Balance will always reset back to 10 and will not hold the new value of an increment or decrement.
function Balance() {
var p1_Balance=10;
var x= Math.floor(10*Math.random());
if (x<5) {
p1_Balance=p1_Balance-1;
} else {
p1_Balance=p1_Balance+1;
}
return p1_Balance;
}
Pass p1_Balance into the function instead of initializing it each time the function is called with: var p1_Balance = 10;
p1_Balance should be declared outside the scope of the function (meaning not within the function itself). Otherwise, each time the function is called, the initializer that sets the value to 10 runs as well.
var p1_Balance=10;
function Balance(){ ...
You can use Javascript closures to create a function that does what you want, as you can see below:
var Balance = (function() {
var p1_Balance = 10;
return function() {
var x = Math.floor(10 * Math.random());
if (x < 5)
return p1_Balance += 1;
else
return p1_Balance -= 1;
};
})();
for (var i = 0; i < 10; i++)
console.log(Balance());
Alternatively, you will need to define the p1_Balance variable outside the function or pass it as an argument.
There could be several solutions:
one is declaring p1_Balance as a global variable.
var p1_Balance=10;
function Balance(){
var x= Math.floor(10*Math.random());
if (x<5) {
p1_Balance=p1_Balance-1;
}
else {
p1_Balance=p1_Balance+1;
}
return p1_Balance;
}
another is you could pass balance as a function parameter:
function Balance(p1_Balance){
var x= Math.floor(10*Math.random());
if (x<5) {
p1_Balance=p1_Balance-1;
}
else {
p1_Balance=p1_Balance+1;
}
return p1_Balance;
}
.....
value = Balance(10);// value=something that you want to change by that function.

Object function scope

factory(n) returns objects with functions.
func1 function definition creates its own scope, and x inside this function references x = n + ''.
But func2 is a reference and the scope is wrong.
Is there a way to return an object from create so its functions were references (not separate definitions)?
Actually, I'm fine with func1 approach while function definition footprint is small. If it is a complex function it would be better not to clone this function into every object comming from factory(n). inner_func may not use this, it is simple function. Also I want to avoid new and this.
var factory = (function(){
var x = '!';
return function create(n){
var x = n + '';
return {
func1: function(y){return inner_func(x, y); },
/* vs */
func2: inner_func_api
}
}
function inner_func_api(y){ return inner_func(x, y); }
function inner_func(a, b){ return a + b; }
}());
var f1 = factory(2);
var f2 = factory(3);
var f1_func1 = f1.func1(4);
var f2_func1 = f2.func1(5);
var f1_func2 = f1.func2(4);
var f2_func2 = f2.func2(5);
console.log(f1_func1, f2_func1); //24 35
console.log(f1_func2, f2_func2); //!4 !5
You could define that function separately from the object initializer on the return statement:
var factory = (function(){
var x = '!';
return function create(n){
var x = n + '';
function func1(y) {
return inner_func(x, y);
}
return {
func1: func1,
/* vs */
func2: inner_func_api
}
}
function inner_func_api(y){ return inner_func(x, y); }
function inner_func(a, b){ return a + b; }
}());
However, it makes no practical difference, and it doesn't matter how big or complicated that function is. Function instances do take up space, but the code for the function is constant (immutable) and doesn't need to be part of every Function object created from the same piece of source code.

Javascript: Using changing global variables in setTimeout

I am working on Javascript and using firefox scratchpad for executing it. I have a global index which I want to fetch inside my setTimeout (or any function executed asynchronously). I can't use Array.push as the order of data must remain as if it is executed sequentially. Here is my code:-
function Demo() {
this.arr = [];
this.counter = 0;
this.setMember = function() {
var self = this;
for(; this.counter < 10; this.counter++){
var index = this.counter;
setTimeout(function(){
self.arr[index] = 'I am John!';
}, 100);
}
};
this.logMember = function() {
console.log(this.arr);
};
}
var d = new Demo();
d.setMember();
setTimeout(function(){
d.logMember();
}, 1000);
Here, I wanted my d.arr to have 0 - 9 indexes, all having 'I am John!', but only 9th index is having 'I am John!'. I thought, saving this.counter into index local variable will take a snapshot of this.counter. Can anybody please help me understand whats wrong with my code?
The problem in this case has to do with scoping in JS.
Since there is no block scope, it's basically equivalent to
this.setMember = function() {
var self = this;
var index;
for(; this.counter < 10; this.counter++){
index = this.counter;
setTimeout(function(){
self.arr[index] = 'I am John!';
}, 100);
}
};
Of course, since the assignment is asynchronous, the loop will run to completion, setting index to 9. Then the function will execute 10 times after 100ms.
There are several ways you can do this:
IIFE (Immediately invoked function expression) + closure
this.setMember = function() {
var self = this;
var index;
for(; this.counter < 10; this.counter++){
index = this.counter;
setTimeout((function (i) {
return function(){
self.arr[i] = 'I am John!';
}
})(index), 100);
}
};
Here we create an anonymous function, immediately call it with the index, which then returns a function which will do the assignment. The current value of index is saved as i in the closure scope and the assignment is correct
Similar to 1 but using a separate method
this.createAssignmentCallback = function (index) {
var self = this;
return function () {
self.arr[index] = 'I am John!';
};
};
this.setMember = function() {
var self = this;
var index;
for(; this.counter < 10; this.counter++){
index = this.counter;
setTimeout(this.createAssignmentCallback(index), 100);
}
};
Using Function.prototype.bind
this.setMember = function() {
for(; this.counter < 10; this.counter++){
setTimeout(function(i){
this.arr[i] = 'I am John!';
}.bind(this, this.counter), 100);
}
};
Since all we care about is getting the right kind of i into the function, we can make use of the second argument of bind, which partially applies a function to make sure it will be called with the current index later. We can also get rid of the self = this line since we can directly bind the this value of the function called. We can of course also get rid of the index variable and use this.counter directly, making it even more concise.
Personally I think the third solution is the best.
It's short, elegant, and does exactly what we need.
Everything else is more a hack to accomplish things the language did not support at the time.
Since we have bind, there is no better way to solve this.
The setTimeout doesn't have a snapshot of index as you are expecting. All of the timeouts will see the index as the final iteration because your loop completes before the timeouts fire. You can wrap it in a closure and pass index in, which means the index in the closure is protected from any changes to the global index.
(function(index){
setTimeout(function(){
self.arr[index] = 'I am John!';
}, 100);
})(index);
The reason is that by the time settimeout is started, the for loop is finished executing the index value is 9 so all the timers are basically setting the arr[9].
The previous answer is correct but the source code provided is wrong, there is a mistyping elf in place of self . The solutions works.
An other way , without a closure , is to just add the index parameter to the function declaration in the setTimeout statement
function Demo() {
this.arr = new Array();
this.counter = 0;
this.setMember = function() {
var self = this;
for(; this.counter < 10; this.counter++){
var index = this.counter;
setTimeout(function(){
self.arr[index] = 'I am John!';
}(index), 100);
}
};
this.logMember = function() {
console.log(this.arr);
};
}
var d = new Demo();
d.setMember();
setTimeout(function(){
d.logMember();
}, 1000);

Generated functions keep reference to variable instead of value replacement?

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);
}
}() );
}

call javascript object method from html

I'm relatively new to Javascript programming. I'm working on an example and am having difficulty in invoking a method on an object from HTML. I suspect this has something to do with the scoping or externalization of the methods, but I'm not sure.
index.html:
<script type="text/javascript">
var f = new Fred();
f.bar();
f.foo();
</script>
Fred.js:
function Fred() {
this.a = 1;
function foo() {
if (a == 1) {
a++;
}
var e = 0;
}
this.bar = function () {
var a = 3;
var b = 4;
};
this.c = 3;
this.d = 4;
}
The call to bar() works, the call to foo() does not.
Yes, you are right, this does have to do with scoping and the concept of closures. You can think of the foo() function as being a "private" method if you are familiar with other object oriented languages like Java or C#. It is only available inside the scope of your Fred() object. The bar() function is "public" in the sense that declaring it with this.bar adds it to the publicly available properties of your Fred() object. So, to also make foo() "public", then declare it as:
this.foo = function () {
if (a == 1) {
a++;
}
var e = 0;
}
For a more in depth explanation of closures in javaScript, try this link: http://www.sitepoint.com/javascript-closures-demystified/
your not assigning a function pointer to foo. Change it to
this.foo = function() {
if (a == 1) {
a++;
}
var e = 0;
};
like you've done:
this.bar = function () {
var a = 3;
var b = 4;
};

Categories