function that makes another function only executable once in JS - javascript

I have been working to create a function that given another function will make that second function only callable once. not unlike the _.once() function.
the desired outcome is the following:
const oneTimeFunction = _.once(function(string) { string.split(''); })
oneTimeFunction('hello')
//returns: 'olleh', and if called again it would have no effect returning the same thing a the original call.
Currently this is what I have:
_.once = function (func) {
var called = 0;
let args = null;
if (arguments.length > 1) {
args = Array.prototype.slice.call(arguments,1);
}
return function () {
if (called === 0) {
console.log('being called');
called ++;
if (!args) {
console.log('without apply');
return func.call(arguments);
} else {
console.log('with apply');
return func.apply(this,args);
}
} else {
console.log('this has been called');
return null;
}
};
};
I am running into a wall as it is returning error type undefined even with everything I have tried. Any help, even to get to where it can call the function regardless of the one time only stipulation? Thanks!

create a variable that count how much this function is called
let count = 0;
function once(str) {
if(count < 1){
count++;
return str.split("").reverse().join("");
}
else return str;
}
console.log(once("hello")); // olleh
console.log(once("hello")); // hello
console.log(once("hello")); // hello

In reading your question, I'm seeing that you would like to always return the first value on subsequent calls:
"if called again it would have no effect returning the same thing a[s] the original call."
So I believe you want to do something like this:
function computeOnce(myFn) {
let origVal = undefined;
return function (...args) {
// if this is not set, this is the first call
if (!origVal) {
// execute the function and store it's return value
origVal = myFn(...args);
}
return origVal;
}
}

Related

is it possible to return a value from a function to a function parameter? js

so I noticed that when you use .addEventListener() you can get its event array like this:
document.getElementById("elementID").addEventListener("click",function(event) {
console.log(event);
});
Is there any way I can create my own function like this? I tried this before but I completely forgot how I managed to do it.
Right now I am trying
function foo(do) {
let a = 0;
setTimeout(do,1);
return a;
}
foo(function(a) {
console.log(a);
});
(results in undefined)
You can pass extra arguments to setTimeout, but note that updating the value in the function does not propagate it back (also note do is a reserved keyword so I changed the name to fn)
function foo(fn) {
let a = 0;
setTimeout(fn,1,a);
return a;
}
const result = foo(function(a) {
console.log(a);
a += 1
});
console.log(result);
So, you can pass an object in instead, and updating that will indeed propagate the change:
function foo(fn) {
let a = {value:0};
//setTimeout(fn,1,a);
fn(a)
return a.value;
}
const result = foo(function(a) {
console.log(a);
a.value += 1
});
console.log(result);
But note that I had to take out the setTimeout and replace it with a direct call to fn(a) - if I would have left that in, the function would have returned before the call to fn was made:
function foo(fn) {
let a = {value:0};
setTimeout(fn,1,a);
return a.value;
}
const result = foo(function(a) {
console.log(a);
a.value += 1
});
console.log(result);
Okay I found a solution:
function foo(event) {
setTimeout(function() {
var a = 0;
event(a);
},1);
}
foo(function(a) {
console.log(a);
});
logs 0
I forgot to mention that I am using code.org and coding with code.org is very very weird. It won't let you do a lot of really cool things like adding arguments for the setTimeout

How to invoke a closure within a function when counting number of times function is invoked

I want to count the number of times a function is called on click. I have this so far but its not quite working. Can anyone help with this?
function test(){
var count = (function({
var i = 0;
return function(){
return i += 1;
}
})();
if(count() == 2){
// do this
}
}
Invoke the function like so:
<select onclick="javascript: test();">
It looks like the count function isn't being invoked properly. How can I invoke the function and perform an operation on it? I want to perform logic at certain numbers of clicks.
var count = 0;
function test(){
count++;
if(count == 2){
// do this
console.log('do something');
}
}
<label onclick="javascript: test();">Test</label>
Take a variable and increment on number of click and do your operation.
You could use a closure to wrap the call.
function countUsage(methodToWrap, methodContext) {
const
wrapContext = methodContext || this;
let
count = 0;
// Return a method, this is the wrapped call.
return function methodWrapper() {
// Increase the counter by 1.
count++;
// Call the original method with the arguments.
methodToWrap.apply(wrapContext, arguments);
// Log the number of times the method was called.
console.log(`The method has been called ${count} times`);
}
}
function methodToWrap(text) {
console.log(`Log line ${text}`);
}
function sumToWrap(a, b) {
console.log(`Sum of ${a} + ${b} = ${a+b}`);
}
const
wrappedLog = countUsage(methodToWrap),
wrappedSum = countUsage(sumToWrap);
// For these three calls you will see the count is increased with each call.
wrappedLog('hello');
wrappedLog('how');
wrappedLog('are you');
// This will result in a log line that there has been 1 call as it is a different method.
wrappedSum(3, 4);
Does this work for you?
var i = 0;
function test(){
var count = (function() {
return function(){
return i += 1;
}
})();
if(count() == 2){
console.log('reached goal')
// do this
}
alert('current count' +i)
}
<select onclick="test()"><option>select</option></select>
And on your item just:
onlick="test()"
You generally had brackets in the wrong place etc and was always setting the value to 0.

When can a function be only called once?

This problem is giving me trouble:
Write a function, once, (see: http://underscorejs.org/#once) that
takes a function and returns a version of that function which can only
be called once. [Hint: you need a closure] You probably don't want to
be able to double charge someone's credit card. Here is an example of
how to use it:
var chargeCreditCard = function(num, price){
//charges credit card for a certain price
};
var processPaymentOnce = once(chargeCreditCard);
processPaymentOnce(123456789012, 200);
Here's how I tried to solve it:
var once = function(func) {
var invoked = 0;
return function() {
if (invoked === 0) {
invoked++;
return func();
}
};
};
The only problem I can see is you are not passing the arguments to the called function. You can use the arguments object and Function.apply() to do this.
var once = function (func) {
var invoked = 0;
return function () {
if (invoked === 0) {
invoked++;
return func.apply(this, arguments);
}
};
};
Demo: Fiddle
You are almost in the right path but you could also store the return value, pass the args and provide the this context:
function once(func) {
var val,
count = 2;
return function () {
if (--count > 0) {
val = func.apply(this, arguments);
} else {
//performance concern
func = null;
}
return val;
};
}
This is what I have borrowed from lodash to use in my codebase.
It is also worth noting that, passing the count variable as an argument would also let us to use it in a way that the func gets called less than count times

A function that takes a callback and creates a new version of the callback that can only be called once. Javascript

I trying to create a function, that takes another function as the argument, and creates a new version of the callback function that can only be called once. Subsequent calls will return the output if the initial call.
This is along the lines of recreating the Underscore .once method.
Here is what I have thus far. I have created a chargeCreditCard function. I want to create a new version of this function that can only be called once (chargeOnce). Explanation is appreciated. Thanks.
Edit. I want the once function to not rely on any code outside of the function to work (ie. an external counter variable).
var chargeCreditCard = function(num, price){
return num*price;
};
function once (func) {
var hasActionBeenCalled = false;
var call = function () {
if(!hasActionBeenCalled) {
hasActionBeenCalled = true;
func;
}
}
}
var chargeOnce = once(chargeCreditCard);
console.log(chargeOnce(2,3));
console.log(chargeOnce(4,5));
Your function once does not return anything, and your function call does not call anything. Make it
function once(func) {
var hasActionBeenCalled = false;
return function() {
if (!hasActionBeenCalled) {
hasActionBeenCalled = true;
return func.apply(this, arguments);
}
}
}
For garbage collection, I'd recommend to do
function once(func) {
var res;
return function() {
if (typeof func == "function") {
res = func.apply(this, arguments);
func = null; // unset func
}
return res;
}
}

Updating an array inside a call back

I have the following two functions:
var abc;
function updateNum() {
abc=0;
g.dbm.transaction("leagues").objectStore("leagues").openCursor(null, "prev").onsuccess = function (event) {
var teams, i;
team.filter({
attrs: ["tid", "abbrev", "region", "name", "cid"],
seasonAttrs: ["winp", "playoffRoundsWon"],
season: g.season
}, function (teams) {
// Sort teams by playoffs and winp, for first round
teams.sort(function (a, b) {
if (a.playoffRoundsWon < b.playoffRoundsWon) {
return -1;
}
if (a.playoffRoundsWon > b.playoffRoundsWon) {
return 1;
}
return a.winp - b.winp;
});
abc+=1;
});
};
}
function getNum() {
return abc;
}
What I am trying to do is update the variable abc inside the callback function and then return it. I do this by first calling the updateNum() function in another file. Then I assign a variable to the value of getNum()
Here is how a sample code would look like:
myFile.updateNum();
var number = myFile.getNum();
I am currently unable to return the updated value of num. number keeps returning 0 (the default value) instead of the newly updated value (which is 1).
How can I get it to show an updated value? Please let me know if I need to add any more information.
Well, if updateNum is async, it would have to take a callback as argument so that you can be notified when the number was updated.
E.g.
var num = 0;
function updateNumAsync(callback) {
setTimeout(function () {
num = 1;
callback && callback(num); //call the callback if provided
}, 500);
}
updateNumAsync(function (num) {
console.log(num); //updated num
});
Here is a general pattern for using an asynchronous function with a callback to pass the asynchronous results around. What is team.filter? You will need to design your code such that the asynchronous portion calls a callback() function that was passed to the enclosing function.
If filtering gives you problems you may want to look at https://github.com/caolan/async#filterarr-iterator-callback
(function main(){
getNum(function(err, abc){
console.log('thx for playing '+abc)
});
})();
function getNum(anotherCallback) {
// Whatever code relies on the result of an asynchronous function must be
// placed inside the callback function
countTeams(function(abc){
console.log('countTeams completed, abc='+abc);
var err = null;
anotherCallback(err, abc);
});
};
function countTeams(callback){
var abc=0;
g.dbm.transaction("leagues").objectStore("leagues").openCursor(null, "prev").onsuccess = function (event) {
var teams, i;
// I don't know what this filter function does, I am assuming it's synchronous
team.filter({
attrs: ["tid", "abbrev", "region", "name", "cid"],
seasonAttrs: ["winp", "playoffRoundsWon"],
season: g.season
}, function (teams) {
// Sort teams by playoffs and winp, for first round
teams.sort(function (a, b) {
if (a.playoffRoundsWon < b.playoffRoundsWon) {
return -1;
}
if (a.playoffRoundsWon > b.playoffRoundsWon) {
return 1;
}
return a.winp - b.winp;
});
abc+=1;
});
return callback(abc); // 0 or n depending on what team.filter does
};
};

Categories

Resources