I'm Using the code below to let my function A only be triggered 3 times.
as I'm new to Javascript I think maybe you guys could show me a better way.
var num = 0;
if(num<4){
function A() {
num++
}
}
I'd put the num check inside the function, in case you want to call it anywhere else it will check your num record when you call it instead of having it automatically run 3 times when you start your program.
var num = 0;
function A() {
if(num<4){
//perform whatever you want your func to do
num++;
} else {
console.log("You performed this function 3 times already");
}
}
This depends highly on what you want to achieve, but one way is using recursion:
function foo(param1, param2, count = 3) {
if (count > 0) {
// ... some code ...
return foo(param1, param2, count-1)
}
return null; // just as example and check for the null later
}
Related
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 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.
I'm sorry if this is a horrible question, I'm a beginner to JS.
So what I'm trying to do is have a function that runs right away and then that function will run other functions if a certain thing is true.
But, when I run it, it says that the function is not yet defined and I can't figure out how to solve this problem. I thank you for your time.
function start() {
var start = prompt('Yes or no?');
if (start === 'Yes') {
yes();
}
but because its in the beginning the functions it runs are below it and are not able to run.
//declare a function called yes
var yes = function(){
alert('You said yes');
};
function start() {
var start = prompt('Yes or no?');
if (start === 'Yes') {
yes();
}
}
start(); //call first function
Passing function as a parameter example.
var fun1 = function(callback) {
var res = prompt('Your ans please');
callback(res);//pass response to function.
};
var handleRes = function(res){
if (res==='yes'){
alert('you said yes');
}
else if(res==='no'){
alert('you said no');
}
else {
alert('you did not say yes or no');
}
};
//call fun1 pass handleRes function to it for callback
fun1(handleRes);
Order in which you write your function matters in JavaScript in some scenarios. Probably the function you are calling is written below it.
In one of Douglas Crockford speeches, He favours the use of tail recursion over loops. this code was presented,
function repeat(myFunc) {
if (myFunc !== undefined) {
return repeat(myFunc);
}
}
I thought to define a myFunc but don't know if a static counter can retain its state during function calls or use a global counter. but being new to javascript I wanted to ask first. How can this be used in an example, say to count down from 10 to 0? Thanks.
You need to call the function myFunc somewhere -- and evaluate the result for further call of repeat.
function repeat(myFunc) {
if (myFunc()) {
repeat(myFunc);
}
}
var count = 10;
repeat(function () {
document.write(count + '<br>');
count--;
return count >= 0;
});
Here is a version that keeps state without global variable:
function repeat(myFunc, arg) {
if ((arg = myFunc(arg)) !== undefined) {
repeat(myFunc, arg);
}
}
repeat(function (count) {
document.write(count + ',');
count--;
if (count >= 0) return count;
}, 10);
How can this be used in an example, say to count down from 10 to 0?
Pass a Number to repeat, call repeat with decremented number as parameter until variable parameter is equal to 0
function repeat(n) {
console.log(n)
if (n) {
return repeat(--n);
}
}
repeat(10)
Not sure if I understand what approach you want, but you can use this to count down recursively
function repeat(myFunc, times) {
if(times > 0 && typeof myFunc == 'function') {
myFunc(times);
repeat(myFunc, times-1);
}
}
repeat(alert, 10);
I want call few function one after another recursively with setTimeout.
var flag = 0 ;
function slave1(){
if(flag < 60) {
var COPY_PO_LINE_DIV = document.getElementById("DOM_ELEMENT1"); // Checking if DOM has loaded or not. If yes then doing something.
if (COPY_PO_LINE_DIV != null) {
flag = 0;
//doing something
} else {
setTimeout(slave1,2000); //waiting for 2 seconds and checking again.
}
}
}
//doing similar task
function slave2(){
if(flag < 60) {
var COPY_PO_LINE_DIV = document.getElementById("DOM_ELEMENT2");
if (COPY_PO_LINE_DIV != null) {
flag = 0;
//doing something
} else {
setTimeout(slave2,2000);
}
}
}
function master() {
slave1();
console.log("Without completing slave1 function.");
slave2();
}
Through master() function I want to call multiple functions one after another, however in current situation its calling slave2() without completing slave1(). How can I make sure that slave1() has executed completed. If DOM element is not loaded than it should execute 60 times after every 2 seconds and than it should come out from slave1() and go to next one.
I want to execute same function for 60 times if dom element is not loaded without returning the control to next function.
You need to adjust slave1 to run a callback when it is finished which will be slave2.
function slave1(callback){
if(flag < 60) {
var COPY_PO_LINE_DIV = document.getElementById("DOM_ELEMENT1"); // Checking if DOM has loaded or not. If yes then doing something.
if (COPY_PO_LINE_DIV != null) {
flag = 0;
//doing something
callback();
} else {
setTimeout(slave1,2000); //waiting for 2 seconds and checking again.
}
}
}
function slave2(){...}
function master() {
slave1(slave2);
console.log("Without completing slave1 function.");
}
This is your basic javascript chaining. If you have more slaves you might want to look into async.series otherwise you go into callback hell as Gabs00 has put it nicely:
slave1(function(){
slave2(function(){
slave3(function(){
slave4(slave5);
});
});
});
If you need to pass values to callbacks then you need to use an intermediate anonymous function which in turn calls the intended callback with the arguments in question. To do that, you need define your functions so that they use the arguments:
function slave1(str, callback){...}
function slave3(i, callback){...}
slave1("some argument", function(){
slave2("another argument", function(){
slave3(1, function(){
slave4(2, slave5);
});
});
});
Consider using promises for things like that. Here an implementation on top of jQuery, other promise libraries work similarly.
function waitForElement(elementId, maxTries, checkInterval) {
var d = $.Deferred(), intvalID, checkFunc;
// set up default values
maxTries = maxTries || 60;
checkInterval = checkInterval || 2000;
checkFunc = function () {
var elem = document.getElementById(elementId);
if (maxTries-- > 0 && elem) {
clearInterval(intvalID);
d.resolve(elem);
}
if (maxTries <= 0) {
clearInterval(intvalID);
d.reject(elementId);
}
};
// set up periodic check & do first check right-away
intvalID = setInterval(checkFunc, checkInterval);
checkFunc();
return d.promise();
}
Now, if you want to test for elements one after another, you can cascade the calls like this:
function master() {
waitForElement("DOM_ELEMENT1").done(function (elem1) {
waitForElement("DOM_ELEMENT2").done(function (elem2) {
alert("elem1 and elem2 exist!");
// now do something with elem1 and elem2
}).fail(function () {
alert("elem1 exists, but elem2 was not found.");
});
}).fail(function () {
alert("elem1 not found.");
});
}
or you can do it in parallel and have a callback called when all of the elements exist:
function master() {
$.when(
waitForElement("DOM_ELEMENT1"),
waitForElement("DOM_ELEMENT2")
)
.done(function (elem1, elem2) {
alert("elem1 and elem2 exist!");
// now do something with elem1 and elem2
})
.fail(function () {
alert("not all elements were found before the timeout");
});
}
Your slave2 function should be passed to slave1 function as a callback and should be called in slave1 after it finishes (if ever?). Your current situation is quite common, since setTimeout() function is asynchronous, thus JS interpreter doesn't wait till the function is completed, but sets the setTimeout() result at the end of the Evet Loop and continues processing the master() method.
In order to pass arguments to functions, creating anonymous functions turns out to be an overkill. Consider using "bind" instead. So, if you've got
function slave1(str, callback){...}
function slave2(str, callback){...}
function slave3(i, callback){...}
function slave4(i, callback){...}
function slave5()
Instead of using
slave1("some argument", function(){
slave2("another argument", function(){
slave3(1, function(){
slave4(2, slave5);
});
});
});
Consider using
slave1("some argument",
slave2.bind(null, "another argument",
slave3.bind(null, 1,
slave4.bind(null, 2, slave5)
)
)
);
Much easier, more efficient in terms of memory and CPU utilization.
Now, how to do this with setTimeout:
slave1("some argument",
setTimeout.bind(null, slave2.bind(null, "another argument",
setTimeout.bind(null, slave3.bind(null, 1,
setTimeout.bind(null, slave4.bind(null, 2,
setTimeout.bind(null, slave5, 0)
),0)
),0)
),0)
);
I explained the problem in more detail at
http://morethanslightly.com/index.php/2014/09/executables-the-standard-solution-aka-mind-the-bind/