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
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.
What you're missing is removing the original function after the first execution. You should modify your code in the following way:
function once(func) {
let num;
function retFunc(x){
if (func)
num = func(x);
func = null;
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
This way you remove the function after first usage and you're just keeping the result.
This is your problem
function retFunc(x){
num = func(x);
return num;
}
You're always calling func(x)
. Add an if condition to check if num
is undefined
before calling func(x)
.
different approach: overwrite the call to func
no flags, check if result is undefined or anything required
function once(func) {
let num;
let internalFn = function(x) {
num = func(x);
internalFn = function(x) {
return num;
}
return num;
}
function retFunc(x){
return internalFn(x);
}
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