Function Definitions as Arguments - javascript

var cancel = setTimeout(function(){clearTimeout(cancel);}, 500);
var cancel = setTimeout(clearTimeout(cancel), 500);
Scholastic question: The first of these two expressions work, while the second does not. The setTimeout() method is accepting a function and a duration as its arguments and both of these examples are clearly providing that. The only difference is that the first is a function definition while the second is a function invocation.
If functions designed to take a function as an argument can only handle function definitions, how do you go about providing that function with the variables it may need? For example:
stop = function(y){clearInterval(y)};
count = function(x){
var t = 0,
cancel = setInterval(function(){console.log(++t);},1000);
setTimeout(stop(cancel),x);
};
count(5000);
The function above doesn't work because it's invoking the function
stop = function(){clearInterval(cancel)};
count = function(x){
var t = 0,
cancel = setInterval(function(){console.log(++t);},1000);
setTimeout(stop,x);
};
count(5000);
The function above doesn't work because the stop() doesn't have access to the cancel variable.
Thank you in advance for attempting to educate me on the work-around for this type of issue.

The setTimeout() method is accepting a function and a duration as its
arguments and both of these examples are clearly providing that. The
only difference is that the first is a function definition while the
second is a function invocation.
Yes but when you invoke a function you return the result which could be a string, integer, etc..., so you are no longer passing a function pointer but some string, integer, ... which is not what the setTimeout function expects as first argument.
Think of the second example like this:
var result = clearTimeout(cancel); // result is now an integer
setTimeout(result, 500); // invalid because setTimeout expects a function pointer
If functions designed to take a function as an argument can only
handle function definitions, how do you go about providing that
function with the variables it may need?
You could use closures:
var stop = function(y) { clearInterval(y); };
var count = function(x) {
var t = 0,
var cancel = setInterval(function() { console.log(++t); }, 1000);
setTimeout(function() { stop(cancel); }, x);
};
count(5000);
or simply:
var count = function(x) {
var t = 0,
var cancel = setInterval(function() { console.log(++t); }, 1000);
setTimeout(function() { clearInterval(cancel); }, x);
};
count(5000);

You get around it exactly as you have in the first line of code by wrapping the function call with an anonymous function.

Try passing in the cancel variable to the anonymous function.
stop = function(cancel){clearInterval(cancel)};
count = function(x){
var t = 0,
cancel = setInterval(function(){console.log(++t);},1000);
setTimeout(stop(cancel),x);
};
count(5000);

Local variables are always injected into nested scopes, for example those introduced by function declarations via function () { }. This is what is commonly called a closure and it forms an important tool in Javascript programming.
Therefore, setTimeout( function() { stop(cancel); },x); will do, the inner function has access to the cancel variable defined in the outer scope (it can even change its value).

Related

Implementing a delay function using setTimeout() with passing optional arguments (Javascript)

I am trying to get to grips with Javascript by implementing intermediate functions from scratch. Currently trying to implement a delay function that executes an arbitrary function passed as an argument after a waiting time (wait). This also needs to be able to forward additionally passed arguments as extra arguments for the function being delayed.
What I have made so far isn't calling the function within the setTimeout(). Im not sure if its a syntax error or ive just missed the point completely. I have looked through similar questions on here and tried to implement some of the suggested results, however none seem to take the additional arguments aspect into consideration. Anyway, here is what I currently have.
var exampleDelay = function (func, wait) {
return function () {
setTimeout(func.apply(this, arguments), wait);
}
};
Any help tackling this would be appreciated (or if anyone can point me to an answer I may have missed).
Fran beat me to it but just for variety.
if you want to supply all the params at once this might be an option
var exampleDelay = function(callback,wait,args) {
var args = [].slice.call(arguments) // get the parent arguments and convert to an array
args.splice(0,2); // remove the first two argument which are the fuction supplied and the wait time
// a fuction to call the supplied function
var callnow = function() {
var params = arguments; // get the child arguments
var context = this;
setTimeout(function(){
callback.apply(context, params) // call the function
}, wait);
}
callnow.apply( this, args ) // use apply to supply the arguments extracted from the parrent
};
exampleDelay(console.log, 1000,"hey")
exampleDelay(console.log, 5,"hey", "there")
callnow.apply( this, args ) // we then call the function with apply and supply args extracted from the parent
well, you can handle function validation later to make sure that the first argument is a function
The function you return from exampleDelay is the one you call later one.
To preserve the arguments at the time of calling that function until the time the timer executes it you can wrap the intended function in an anonymous function within the timer. Then inside you can use apply to pass the previously stored arguments. Similar to the below.
var exampleDelay = function(func, wait) {
return function() {
var params = arguments;
var context = this;
setTimeout(function(){
func.apply(context, params)
}, wait);
}
};
var func1 = function(a, b) {
console.log(a + b);
}
var func2 = function(a, b, c) {
console.log(a, b, c);
}
var x = exampleDelay(func1, 1000);
var y = exampleDelay(func2, 2000);
x(12, 15);
y('How', 'Are', 'You?');

Recall a function without re-initializing every time

I'm trying to call a function without re-initializing (hope I used the correct word here) it every time I call it. So the first time it gets called, it should initialize, but after its initialized, it should just use that reference.
Here's the code I'm trying to do it with.
JSFiddle
console.clear();
function mainFunction(e) {
var index = 0;
function subFunction() {
console.log(index++);
}
return subFunction();
}
window.addEventListener('click', mainFunction)
index should increase by one every time mainFunction gets called. The obvious solution, is to make index a global variable (or just out of mainFunction). But I need index to stay inmainFunction`.
How can I make index increment every time (using the same reference) mainFunction gets called?
I tried assigning mainFunction to a variable, then calling the variable in the event listener,
var test = mainFunction;
window.addEventListener('click', test)
but that didn't work. The results were the same.
You should correct the code as follows;
console.clear();
function mainFunction(e) {
var index = 0;
function subFunction() {
console.log(index++);
}
return subFunction; // <<< don't invoke subfunction
}
window.addEventListener('click', mainFunction()) // <<< invoke mainfunction
maybe try closures?
var main = (function () {
var index = 0;
return function () {return index += 1;}
})();
main()
main()
//index should be 2...
explain-
The variable main is assigned the return value of a self-invoking function.
The self-invoking function only runs once. index initialize only once.
If you don't want to make index global (or one scope higher regarding mainFunction), you can use a closure:
var mainFunction = (function () {
var index = 0;
return function () {return console.log(index++);}
})();
<button onclick="mainFunction()">Click</button>
Using OOP concept is the proper way to achieve this. The following should help you.
If you want to do it in ES6 way follow this babel example
var mainFunction = function(val) {
this.index = val //initialize this with the fn parameter or set a atatic value
}
mainFunction.prototype.subFunction = function() {
return this.index++
}
var instance = new mainFunction(0)
window.addEventListener('click', function() {
console.log(instance.subFunction())
})
<p>Click to see the result </p>

Can I put a method as the argument in the setInterval function?

Preety straight forward question, though I can't find the answer anywhere
I tried these two ways:
setInterval(function(){object/*or this*/.method()},500)
and
setInterval('object/*or this*/.method()',500)
setInterval in fact expects a method as the first argument, though there is an alternative syntax where the first argument can be a string of code (not recommended by most)
If you're having issues with that code, it may have to do with the scope of 'this'
setInterval(function(){this.method()},500)
In the above code, 'this' will refer to the closure itself, and wouldn't be the same as 'this.method' occurring outside of that closure. For example, the following would work:
function MyClass() {
this.thingy = 'yep this is a thingy'
}
var myClass = new MyClass()
// Will log 'MyClass yep this is a thingy'
setInterval(function() { console.log('MyClass', myClass.thingy) }, 1000)
Whereas the following will not work (presuming instantiating the object and calling foo()):
function MyOtherClass() {
this.thingy = 'also a thingy'
}
// Will log 'MyOtherClass undefined'
MyOtherClass.prototype.foo = function() {
setInterval(function() { console.log('MyOtherClass', this.thingy) }, 1000)
}
The second example will work if we get around using 'this' within the closure (presuming instantiating the object and calling bar()):
MyOtherClass.prototype.bar = function() {
var that = this
setInterval(function() { console.log('MyOtherClass', that.thingy) }, 1000)
}
Also be sure that setInterval is being passed the name of a function:
setInterval(someFunction, 500)
rather than executing a function as an argument
setInterval(someFunction(), 500)
This last line of code is usually a mistake, unless someFunction() returns a function itself ;)
The difference between your 2 ways for passing a function to setInterval is whether you want to pass your function as refrence of just copy of it. Allow me to explain it by example:
-1 Referring(demo):
var obj = {
testMethod: function () {
console.log('function (testMethod): intial output');
}
}
setInterval(function () {
obj.testMethod()
}, 1000);
obj.testMethod = function () {
console.log('function (testMethod): changed output');
}
when you run this code, the result 'll be execution of the modified version of testMethod. Because here you dont copy the function! Instead, you refer to it. So whenever function implementation is changed, the last modified version is executed.
-2 Copying(demo):
var obj = {
testMethod: function () {
console.log('function (testMethod): intial output');
}
}
setInterval(obj.testMethod, 1000);
obj.testMethod = function () {
console.log('function (testMethod): changed output');
}
Here all you do is you are passing a copy of the last defined version of the function testMethod to setInterval. So whatever changes you do to testMethod, the result of setInterval will not be changed.

setInterval exits after first iteration. Please help me rectify this snippet?

Can someone help me rectify the issue related to the setInterval? I'm fairly new to JavaScript, I'm not sure what's wrong here. I have this block in my page:
GlobalTicker.prototype.TickElements = function () {
this.timer = setInterval(this.initializeElement.apply(this) , 1000);
};
GlobalTicker.prototype.initializeElement = function () {
for (var i = 0; i < this.tickerElements.length; i++) {
var existingRun = this.tickerElements[i].secs;
var elementId = $('#' + this.tickerElements[i].id + ' .comment-editor').find('.ticker');
existingRun -= 1;
$(elementId).text(existingRun);
if (existingRun === 0) {
$(elementId).remove();
this.tickerElements.splice(i, 1);
if (this.tickerElements.length == 0) clearInterval(this.tickerElements.timer);
}
}
};
Then somewhere in the code, I have this call in a function
var objTicker = new GlobalTicker();
CommentManagement.prototype.createComment = function (domObject) {
objTicker.TickElements();
};
This function call actually invokes the setInterval function and runs the first iteration and jumps to the initialiseComment(); but once this block is executed, on the next interval, instead of executing the initialiseComment(); again, it jumps back to my function call CreateComment();. What am I doing wrong here?
setInterval() requires a function reference. You were calling the function itself and passing the return result from executing the function (which was undefined) to setInterval(). Since that return value is not a function, there was no callback function for setInterval() to call. Thus, your method was executed once when you first called it, but couldn't be called by the interval.
To fix it, you should change from this:
this.timer = setInterval(this.initializeElement.apply(this) , 1000);
to this:
var self = this;
this.timer = setInterval(function() {self.initializeElement()}, 1000);
Note, the value of this will also be different in the setInterval() callback than the value you want so the one you want is saved here in self so it can be referenced from that. There's also no need to use .apply() in this case because calling a method on an object will automatically set the this pointer as needed.

Reassign variables stored in closure using a callback or global function

EDIT
Let me get more to the point. I'm trying to create a psuedo promise implementation. The idea here being that I have a callback that won't be executed until an asynchronous call is received. So I'm simply queueing up all the calls to this function until the time at which it's notified that it can be executed. The queue is emptied and any further call to the function is SUPPOSED to execute immediately, but for some reason, the function is still queueing. This is because, for whatever reason, my redefinition of the runner function is not working correctly. The code below was my sleep deprived, frustrated version of every thought that went through my head. Here's the actual code:
function Promise(callback){
var queue = []
, callback = callback
, runner = function(){
queue.push({
context: this,
args: Array.prototype.slice.call(arguments, 0)
});
}
;//var
runner.exec = function(){
for(var i = 0, ilen = queue.length; i < ilen; i++){
var q = queue[i];
callback.apply(q.context, q.args);
}
runner = callback;
};
return runner;
}
test = Promise(function(){
$('<div/>').appendTo('#output').html(Array.prototype.slice.call(arguments,0).toString());
});
test(1,2);
test(3,4);
test.exec();
test(5,6);​
http://jsfiddle.net/a7gaR/
I'm banging my head against the wall with this one. I'm trying to reassign variables in a function from a call outside the function itself (ideally by passing a reassignment function as a callback). In the example I posted on jsfiddle, I made a global function that, in theory, has a reference to the variables contained within its parent function. Upon calling that external function, I expect it to reassign the values that the other function is using. It doesn't seem to work this way.
window.test = function temp() {
var val = 7,
func = function() {
return val;
};
window.change = function() {
window.test.val = 555555;
$('<div>Changing ' + val + ' to ' + window.test.val +
'</div>').appendTo($output);
val = window.test.val;
temp.val = window.test.val;
func = function() {
return 'Why isn\'t this working?';
}
}
return func();
}
var $output = $('#output');
$('<div/>').appendTo($output).html('::' + test() + '::');
window.change();
$('<div/>').appendTo($output).html('::' + test() + '::');
http://jsfiddle.net/YhyMK/
The second time you call test you're creating a new local variable called func and defining a new window.change that closes over that new variable. The changes you made to the original func by calling the original window.change are not relevant in the second call.
Also note that the following line:
window.test.val = 555555;
...does not modify/refer to the val variable in the outer function. window.test.val refers to a property named val on the test object (which happens to be a function), not any local variable.
You are trying to refer to a local variable in a function with the syntax func.varname. That won't work, that's not the way local variables work.
I finally created a function that would perform this operation. The gist for it is here: https://gist.github.com/2586972.
It works like this...
You make a call to Defer passing the callback whose functionality you'd like to delay:
var deferredCB = Defer(function(){ console.log(this,arguments) };
deferredCB will now store all of the arguments you pass allowing them to be executed at some later date:
defferedCB(1);
defferedCB(2);
Now, when you're ready to perform the operation, you simply "execute" deferredCB:
defferedCB.exec();
Which results in:
// window, 1
// window, 2
All future calls to deferredCB will be executed immediately. And now that I'm thinking about it, I'll probably do a rewrite to allow you to reset deferredCB to it's pre-executed state (storing all the arguments again).
The key to making it work was having a wrapper function. Javascript simply won't let you reassign a function while it's being executed.
TADA!!!

Categories