Javascript closure, calling function different ways - javascript

I'm able to call this closure as so:
var increment = (function () {
var test = 0;
return function () {
test++;
console.log(test);
}
})();
increment(); //1
increment(); //2
However how do I call this using regular function syntax?
function increment() {
var test = 0;
return function () {
test++;
console.log(test);
}
}
increment()(); 1
increment()(); 1

Whenever you call increment() you create a "new counter", so the second example is not the same, you're creating 2 different instances.
You'd have to create an instance first, then use that:
var inc = increment();
inc(); // 1
inc(); // 2

you are returning a function so it would be
var inc = increment();
inc();
inc();
here is a fiddle
http://jsfiddle.net/kkemple/hLQ3x/

Related

Add values on subsequent call in javascript function.?

Let's consider I have the following function call,
function add(){
x = 0 ;
for(i = 0 i < ##; i++){ // need to run a loop four times
x+=1
}
}
Let's consider I am trying to Implement the function that will add one on each subsequent call, like below
console.log(add()()().getValue()); // 3
console.log(add().getValue()); // 1
console.log(add()().getValue()); // 2
A call to add must return a function which also has a getValue method, and each call to that function must return the same thing. So:
function add() {
var x = 1;
function inner() {
x += 1;
return inner;
}
inner.getValue = function () {
return x;
}
return inner;
}
console.log(add()()().getValue()); // 3
console.log(add().getValue()); // 1
console.log(add()().getValue()); // 2
My guess is they were expecting you to use toString() which is not the greatest way of doing this.
function add(x = 0) {
function next() {
return add(x+1);
}
next.toString = function () {
return x;
};
return next;
}
console.log("example 1", add()()()());
console.log("example 2", add()()()()()()()()());
I think you are trying to emulate the behavior of generator functions. Here is a snippet that illustrates one way you could do it with a generator.
function* adder() {
let x = 0;
while (true) {
yield x + 1;
x++;
}
}
const add = adder();
const firstValue = add.next();
const secondValue = add.next();
const thirdValue = add.next().value;

Counting function

I need to have multiple counters so I created a function, the problem is that I can't store the value in the variable outside the function. I thought this would be easy but I couldn't find anything online.
myCounter = 2;
function count(counter) {
counter++;;
}
count(myCounter);
I would get the value in myCounter to update every time I call the function, thanks for any help you can provide
You can use a closure function that returns an object with a getter so you can initialize as many individual instances as you need
function counter() {
let _count = 0;
return {
get count() {
return ++_count;
}
}
}
let ct1 = new counter();
console.log('ct1', ct1.count, ct1.count)
let ct2 = new counter();
console.log('ct2', ct2.count, ct2.count, ct2.count)
Try this.
var myCounter = 2;
var myCounter2 = 3;
function count(counter) {
return ++counter;
}
myCounter = count(myCounter);
myCounter2 = count(myCounter2);
console.log('myCounter: ' + myCounter);
console.log('myCounter2: ' + myCounter2);

Scope in generated Callback function

I have a generater function generation callback functions for eventlisteners:
function createCallback(counter){
return function(){
counter++;
}
}
The callback should just count how ofter a button was clicked. Lets generate two functions:
var counter1 = 0;
var counter2 = 0;
var callback1 = createCallback(counter1);
var callback2 = createCallback(counter2);
And register them as listeners:
button1.addEventListener("click", callback1);
button2.addEventListener("click", callback2);
Now I need a reset function:
function reset(){
counter1 = 0;
counter2 = 0;
}
I would have expected, that the generator function passes the reference to the global counters into the generated callback functions and the callback functions would modifiy the global variables. But they don't, as I learned from the reset function.
There is an issue with scope, but I do not get it.
Why and how do the generated callback functions have an own scope for their counters? EDIT Answer: Because the argument counter passed into the createCallback function is not passed as refernce into the generated function.
How could I bind/access the global counter1 and counter2?
EDIT
Since I already learned, that the 'counter' variable is not passed as reference: How can I generate a function with a reference to a global variable?
You can use an object to store the counters and pass property names around:
const counters = {
a: 0,
b: 0
};
function createCallback(counterName){
return function(){
counters[counterName]++;
}
}
button1.addEventListener("click", createCallback("a"));
button2.addEventListener("click", createCallback("b"));
function reset(){
counters.a = 0;
counters.b = 0;
}
(If you don't need individual names, use an array with indices instead)
The alternative is to create multiple closures over the same variable for the different functionalities, and keep them in one object per counter. That's the OOP way:
function createCounter() {
var counter = 0;
return {
getCount() {
return counter;
},
reset() {
counter = 0;
},
increment() {
counter++;
}
};
}
const counter1 = createCounter();
const counter2 = createCounter();
button1.addEventListener("click", counter1.increment);
button2.addEventListener("click", counter2.increment);
function reset(){
counter1.reset();
counter2.reset();
}
(again, use an array of counters instead of multiple individually named variables if you need arbitrarily many)
Objects in JS are pased by reference (by reference value actually), so this will work (setTimeouts are used here to simulate the callbacks)
function createCallback(counter){
return function(){
counter.count++;
}
}
function reset(){
counter1.count = 0;
counter2.count = 0;
}
var counter1 = {count: 0};
var counter2 = {count: 0};
var callback1 = createCallback(counter1);
var callback2 = createCallback(counter2);
setTimeout(function(){
callback1();
document.getElementById('result').innerHTML += counter1.count + ' ';
}, 1000);
setTimeout(function(){
callback1();
document.getElementById('result').innerHTML += counter1.count + ' ';
}, 2000);
setTimeout(function(){
callback1();
document.getElementById('result').innerHTML += counter1.count + ' ';
}, 3000);
setTimeout(function(){
reset();
document.getElementById('result').innerHTML += counter1.count + ' ';
}, 4000);
<div id="result"></div>
In Javascript, primitive type variables like strings and numbers are always passed by value.
So you could use object instead of primitive vars:
Embed your global var inside an object:
var myCounterObj = {
counter1: 0,
counter2: 0
}
Change your callback definition in this way:
function createCallback(counter, name) {
return function() {
counter[name]++;
console.log("My counter is: " + counter[name]);
}
}
Then create the callback vars:
var callback1 = createCallback(myCounterObj, 'counter1');
var callback2 = createCallback(myCounterObj, 'counter2');
And finally change the reset function:
function reset() {
myCounterObj.counter1 = 0;
myCounterObj.counter2 = 0;
}
Hope this helps!
The variable counter (counter1, counter2) is passed by value, bot by reference. To make it work, the variables should be changed into objects:
var counter1 = {"value": 0};
var counter2 = {"value": 0};
Those can be passed into the generator function. The increment has to be changed accordingly:
function generate(counter){
return function(){
counter.value++;
}
}
As well as the reset function:
function reset(){
counter1.value = 0;
counter2.value = 0;
}
Now it works.

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.

Closure for setInterval function in 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);
}

Categories