Hello I have a code here:
/* example counter app */
const incrCounter = () => {
let count = 0;
return () => {
return ++count;
}
}
/* now use the counter */
incrCounter()();
incrCounter()();
alert(incrCounter()()); // expect 3 but gets 1
I expect to get an alert that says 3 but I get 1 instead.
I got a live demo here:
https://jsfiddle.net/gunitinug/L9nrt085/1/
Thanks.
Every time incrCounter is called, you get a function in return which closes over a count variable that was just created. If you call incrCounter 3 times, you get 3 separate count variables, in different closures.
Call it once to get the function that closes over a single binding of count, then call that function 3 times, so that that one binding is incremented 3 times:
const makeCounter = () => {
let count = 0;
return () => {
return ++count;
}
}
const counter = makeCounter();
counter();
counter();
console.log(counter());
Giving the function more accurate names will make things more understandable as well - like above, you could call the function-that-returns-a-function makeCounter, and call the returned function counter.
The count variable should be outside the function to retain its value
/* example counter app */
let count = 0;
const incrCounter = () => {
return () => {
return ++count;
}
}
/* now use the counter */
incrCounter()();
incrCounter()();
alert(incrCounter()());
Thanks for all your input guys.
On closer inspection I could do this:
/* example counter app */
const incrCounter = (() => {
let count = 0;
return () => {
return ++count;
}
})();
/* now use the counter */
incrCounter();
incrCounter();
alert(incrCounter());
More flexible version in my opinion.
const makeCounter = (count = 0) => () => ++count
const counter = makeCounter(5);
console.log(counter()); // 6
console.log(counter()); // 7
console.log(counter()); // 8
console.log(counter()); // 9
Related
Is it possible to create a Spy function that returns an object that keeps track of how many times a function is called like shown below?
var spy = Spy(console, 'error')
console.error('calling console.error')
console.error('calling console.error')
console.error('calling console.error')
console.log(spy.count) // 3
You could wrap the call to the method
class Spy {
constructor(obj, method) {
this.count = 0
const _method = obj[method] // save the ref to the original method
const self = this
// wrap the method call with additional logic
obj[method] = function () {
self.count++
_method.call(this, ...arguments)
}
}
}
var spy = new Spy(console, "error")
console.error("calling console.error")
console.error("calling console.error")
console.error("calling console.error")
console.log(spy.count) // 3
you can use javascript Clouser property.
// Initiate counter
let counter = 0;
// Function to increment counter
function add() {
counter += 1;
}
// Call add() 3 times
add();
add();
add();
// The counter should now be 3
reference https://www.w3schools.com/js/js_function_closures.asp
Why in Example 1 and Example 2 return different results?
A conter variable(example 1) instance still has access from the global scope.
Example 1:
const increment = (()=> {
let counter = 0;
//console.log(counter);
const credits = (num) => console.log(`I have ${num} credit(s).`);
return () => { counter++; credits(counter); }
})();
increment();//I have 1 credit(s).
increment();//I have 2 credit(s).
Example 2:
function a() {
let counter = 0;
const credits = (num) => console.log(`I have ${num} credit(s).`);
return () => { counter++; credits(counter); }
}
a()();//I have 1 credit(s).
a()();//I have 1 credit(s).
Thanks.
The let counter line initializes a counter variable. This will occur whenever that line runs.
In the first example, you run that line once when you invoke the IIFE with })() at the end, and the function returned by the IIFE references that one counter variable you initialized.
In the second example, you run that line every time the a function runs - a new counter variable is created every time you do a(). So if you do a()(), you create one counter variable, increment it in the returned function, log it, and then discard it (since the counter can't be referenced by anything anymore). Calling a()() and then a()() results in two separate counter variables, both of which you increment by 1 and log.
If you wanted to log 2 by tweaking the second example, assign the returned function to a variable before calling it, then call that returned function twice (instead of calling a twice).
function a() {
let counter = 0;
const credits = (num) => console.log(`I have ${num} credit(s).`);
return () => { counter++; credits(counter); }
}
const fn = a();
fn();//I have 1 credit(s).
fn();//I have 2 credit(s).
In summary I have the following code:
let incrementer = (function() {
let counter = 0;
let IncreaseCounter = () => {
return counter += 5;
}
return IncreaseCounter;
})();
console.log(incrementer); // function body () => {}
console.log(incrementer()) // 5
console.log(incrementer()) // 10
console.log(incrementer()) // 15
incrementer doesn't work even though i had it wrapped in an IIFE.
Is there any way to print out incrementer as a variable to be incremented each time, without the invocation ()?
Is there any other way in Javascript to achieve such goal other than that closure approach?
Learning some basic concepts in JavaScript "asynchronicity" from Frontendmasters course JavaScript: The Hard Parts, v2
I am given the exercise (Challenge 5):
Create a function limitedRepeat that console logs "hi for now" every second, but only for 5 seconds. Research how to use clearInterval() if you are not sure how to do this.
And following placeholder was given for this function:
function limitedRepeat() {
//CODE HERE
}
I was able to solve it as following (2 versions):
Version 1
function limitedRepeat() {
var totalLogs = 0;
var logFunc = setInterval(myTimer, 1000)
function myTimer() {
if(totalLogs < 5){
console.log("hi for now");
totalLogs++;
} else {
clearInterval(logFunc);
}
}
}
limitedRepeat(); // should log (every second, for 5 seconds): hi for now
Version 2
function limitedRepeat(totalLogs) {
console.log("hi for now");
var timery = setTimeout(timerable,1000);
function timerable() {
totalLogs++;
if(totalLogs >= 5){
clearTimeout(timery);
} else {
limitedRepeat(totalLogs);
}
}
}
limitedRepeat(0); // should log (every second, for 5 seconds): hi for now
Obviously, I have changed the signature of function in Version 2, so I am curious if there is solution that leverages setTimeout() and clearTimeout() and possibly recursion, that doesn't require signature of function to be changed - in other words for that recursive call set by timeout to somehow memorize how many times was the log printed to console?
With recursion;
function limitedRepeat(count = 0) {
if(count >= 5) return;
console.log('hi')
setTimeout(() => limitedRepeat(++count), 1000)
}
limitedRepeat()
Just make sure you increment before recalling the function.
This is my approach:
var count = 1,
timer = setInterval(limitedRepeat,1000)
function limitedRepeat() {
console.log('Hi for now');
count++;
if(count > 5) clearInterval(timer)
}
Using an inner named IIFE with recursion.
EDIT: We don't even need the closure to memoize the times executed if we pass the parameter to the inner function.
function limitedRepeat() {
const maxTimes = 5;
return (function _limitedRepeat(current) {
console.log("hi for now");
var timery = setTimeout(timerable, 1000);
function timerable() {
current++;
if (current >= maxTimes) {
return
}
_limitedRepeat(current);
}
})(0);
}
limitedRepeat();
I would like to periodically call a function (assume it's name is "alter(id)") with the parameter changing every call. The parameter should increment with every call and return to 0 at some point. On a timeline it would look like this:
Time: function to call
0ms: alter(0)
300ms: alter(1)
600ms: alter(2)
900ms: alter(3)
1200ms: alter(0)
1500ms: alter(1)
and so on ad infinitum.
let counter = 0; // closure
const INTERVAL = 300;// 300ms
const alter = (arg) => { /* alter function body */ }
const tick = () => {
counter = alter(counter);
counter = a < 3 ? a + 1: 0;
}
tick(); // 0ms
setInterval(tick, INTERVAL); // call each 300 ms
setInterval documentation
closure