I want to write a function once
that accepts a callback as input and returns a function. When the returned function is called the first time, it should call the callback and return that output. If it is called any additional times, instead of calling the callback again it will simply return the output value from the first time it was called.
Below is what I have tried to do. But I am not getting the results as I expected. I need to understand this concept.
function once(func) {
let num;
function retFunc(x){
num = func(x);
return num;
}
return retFunc;
}
function addByTwo(input){
return input + 2;
}
var onceFunc = once(addByTwo);
console.log(onceFunc(4)); //should log 6
console.log(onceFunc(10)); //should log 6
console.log(onceFunc(9001)); //should log 6
Memoization is actually a specific type of caching. While caching can refer in general to any storing technique (like HTTP caching) for future use, memoizing specifically involves caching the return values of a function .
Caching is an optimization technique that you can use in your applications to keep recent or often-used data in memory locations that are faster or computationally cheaper to access than their source.
cache can do much more (it works on function with any arguments, properties, any type of methods, and even classes...).
You should only assign num = func(x)
when num
is undefined
- that is, on the very first call of retFunc
:
function once(func) {
let num;
function retFunc(x){
if (num === undefined) {
num = func(x);
}
return num;
}
return retFunc;
}
function addByTwo(input){
return input + 2;
}
var onceFunc = once(addByTwo);
console.log(onceFunc(4)); //should log 6
console.log(onceFunc(10)); //should log 6
console.log(onceFunc(9001)); //should log 6
But this isn't a guaranteed general solution - what if the passed function (addByTwo
in your example) results in undefined
when called? Then, the === undefined
check won't work. So, it might be better to set a flag or something similar, and reassign that flag the first time the callback is called:
function once(func) {
let num;
let done = false;
function retFunc(x){
if (!done) {
done = true;
num = func(x);
}
return num;
}
return retFunc;
}
function returnsUndefinedOn1(input){
return input === 1 ? undefined : input;
}
var onceFunc = once(returnsUndefinedOn1);
console.log(onceFunc(1));
console.log(onceFunc(10));
console.log(onceFunc(9001));
You should only call the function and assign num
if it's undefined, otherwise you overwrite it every time:
function once(func) {
let num;
function retFunc(x) {
num = (num === undefined) ? func(x) : num
return num;
}
return retFunc;
}
function addByTwo(input) {
return input + 2;
}
var onceFunc = once(addByTwo);
console.log(onceFunc(4)); //should log 6
console.log(onceFunc(10)); //should log 6
console.log(onceFunc(9001)); //should log 6
Note that if the function you pass in returns undefined
it will be called more than once. If you need to handle that case you can set a flag to indicate whether the cached value is valid.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With