Is it possible to write this without the surrounding "wrapper" anonymous function() ?
So, basicly turn runner(function(){ myfunction('hello world') }, 'Works!!!') into this runner(myfunction('hello world'), 'Works!!!')
JS
function runner(func, something)
{
alert(something);
func();
}
function myfunction(value)
{
alert("I should execute last!");
}
HTML
<button onclick="javascript: runner(function(){ myfunction('hello world') }, 'Works!!!')">Hit me</button>
JS FIDDLE http://jsfiddle.net/pST95/
It turns out that you can do that after all :-) You can use Function.prototype.bind to create a new function object, with the first parameter as the current context and rest of the arguments as the arguments to the actual function.
function runner(func, something) {
console.log(something);
func();
}
function myfunction(value) {
console.log(value);
console.log("I should execute last!");
}
runner(myfunction.bind(this, 'hello world'), 'Works!!!')
Output
Works!!!
hello world
I should execute last!
Is it possible to write this without the surrounding "wrapper" anonymous function()?
To have pre-set parameters you'll need to use a wrapper function one way or another. It's convenient to not need to declare it inline, but all solutions will still require that a wrapper function is used.
The ability to pre-set parameters to a function before it's executed is called "Partial Application". Basically the concept is that you call a function to generate a new function. The new function will call the original function with the correct parameters.
Vanilla JavaScript
Function.prototype.bind allows for additional arguments to be passed after the context which will then be used when the function is eventually called:
runner(myfunction.bind(window, 'hello world'), 'Works!!!');
Of course, IE8 and below don't support this function, so you'll need to use the polyfill to enable this behavior.
jQuery
$.proxy is the cross-browser compatible version in the jQuery library:
runner($.proxy(myfunction, window, 'hello world'), 'Works!!!');
Underscore
_.bind is the cross-browser compatible version in the Underscorejs library:
runner(_.bind(myfunction, window, 'hello world'), 'Works!!!');
however if you want to avoid binding the context when generating the wrapper, underscore also provides a true partial application function.
_.partial will bind the arguments only and allow the context to be determined when the function is executed:
runner(_.partial(myfunction, 'hello world'), 'Works!!!');
What you also can do is use apply or call, so that:
<button onclick="javascript: runner(myfunction,'hello world', 'Works!!!')">Hit me</button>
function runner(func, args, something)
{
alert(something);
func.call(this, args);
}
function myfunction(value)
{
alert("I should execute last!");
}
Your runner function expects a function that takes no arguments because it runs it like this:
func();
So you can't really pass myfunction to it like this:
runner(myfunction, 'Works!!!')
Because you don't have a way to give myfunction an argument (technically it does actually work because your myfunction doesn't use the argument anyway). But if you try this:
runner(myfunction('hello world'), 'Works!!!')
Then all you are doing is calling myfunction directly and sending the returned value (in this case undefined) as an argument to runner and if you look at the console, you should see an error: TypeError: undefined is not a function
So no, you need the wrapper from your original call or you can use Function.prototype.bind as thefortheye suggested.
Related
Is it possible to pass a javascript function with parameters as a parameter?
Example:
$(edit_link).click( changeViewMode( myvar ) );
Use a "closure":
$(edit_link).click(function(){ return changeViewMode(myvar); });
This creates an anonymous temporary function wrapper that knows about the parameter and passes it to the actual callback implementation.
Use Function.prototype.bind(). Quoting MDN:
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
It is supported by all major browsers, including IE9+.
Your code should look like this:
$(edit_link).click(changeViewMode.bind(null, myvar));
Side note: I assume you are in global context, i.e. this variable is window; otherwise use this instead of null.
No, but you can pass one without parameters, and do this:
$(edit_link).click(
function() { changeViewMode(myvar); }
);
So you're passing an anonymous function with no parameters, that function then calls your parameterized function with the variable in the closure
Or if you are using es6 you should be able to use an arrow function
$(edit_link).click(() => changeViewMode(myvar));
Yes, like this:
$(edit_link).click(function() { changeViewMode(myvar) });
You can do this
var message = 'Hello World';
var callback = function(){
alert(this)
}.bind(message);
and then
function activate(callback){
callback && callback();
}
activate(callback);
Or if your callback contains more flexible logic you can pass object.
Demo
This is an example following Ferdinand Beyer's approach:
function function1()
{
function2(function () { function3("parameter value"); });
}
function function2(functionToBindOnClick)
{
$(".myButton").click(functionToBindOnClick);
}
function function3(message) { alert(message); }
In this example the "parameter value" is passed from function1 to function3 through function2 using a function wrap.
This question already has answers here:
addEventListener calls the function without me even asking it to
(5 answers)
Closed last month.
I've noticed a difference between function and function() for addEventListener's callback.
Which isn't a problem till I tried passing a parameter. Basically,
element.addEventListener("hover", logInput, false );
function logInput(){
console.log('registered!');
}
works as intended, but adding parenthesis will cause it log immediately, without continual response to the event trigger:
element.addEventListener("hover", logInput(), false );
function logInput(){
console.log('registered!');
}
Why is this? And how can I get it to work while passing a parameter such as:
element.addEventListener("hover", logOnInput(this), false );
function logOnInput(triggeredElement){
console.log(triggeredElement);
}
(If you really want the triggered element, don't pass anything. this will automatically be set to the triggered element.)
element.addEventListener("hover", logOnInput, false);
function logOnInput(){
console.log(this);
}
To answer your more general question...
There are a few ways to pass a function as an argument with certain arguments already set (this is referred to as "partial application"). If you are able to use modern JavaScript features, the simplest way is probably to use an arrow function.
element.addEventListener("hover", () => logOnInput(foo), false);
function logOnInput(message){
console.log(message);
}
This will only work on very modern browsers. It won't work, for example, in IE 11. In order to support older browsers, you can use the longer form of a function expression.
element.addEventListener("hover", function() {logOnInput(foo);}, false);
function logOnInput(message){
console.log(message);
}
Or you could define a separate function (won't work with this but will work with other variables).
element.addEventListener("hover", logFooOnInput, false);
function logOnInput(triggeredElement){
console.log(triggeredElement);
}
function logFooOnInput() {
logOnInput(foo);
}
Or you could use bind.
element.addEventListener("hover", logOnInput.bind(null, foo), false);
function logOnInput(message){
console.log(message);
}
Its a javascript when you want to call a function you use parentheses. Without parentheses outside a function is useless. But inside a function as argument you use the function without the parentheses so that when that event occurs then only it would run. If you call a function using parentheses inside function argument it will be executed immediately and would also run when the event occurs. To call a function with its parameters inside a function and just to invoke in that event you need to use the bind method like below:
element.addEventListener("hover", logOnInput.bind(null, argument1, argument2, etc), false );
However, if you want to select the context as this then I would recommend you to use like this:
function logOnInput(elem,arguments) {
//now you can use **elem** to refer **this**
}
And use the anonymous function for the hover event like this:
element.addEventListener("hover", function(){
logOnInput(this,arguments)
}, false );
The bind function is probably the cleanest option if you are targeting on modern browsers only. Some blogs talk about the loss of performance comparing bind with anonymous functions. Some blogs talk bad about anonymous functions.
On the anonymous function. All goes well passing arguments on the addEventListener. But when you get to removeEventListener passing the arguments won't work the same way as in the addEventListener.
I found this dude, in 2005, with the answer:
http://www.codingforums.com/dom-and-json-scripting/5909-how-pass-arguments-independently-using-addeventlistener.html
In resume, set your anonymous function to be equal to a newly declared "thing". Idk if this is a var or an expression. I tested var and it wont' work. Idk the technicalities of this at this point, but it works.
function addhoverIn(SELECTED) {
SELECTED.addEventListener("mouseover", addHIn = function() { hoverIn(SELECTED); }, false);
}
function hoverIn(SELECTED) {
SELECTED.removeEventListener("mouseover", addHIn, false);
}
I see
First
$(function() {
...
});
Second
(function() {
})();
Third
function() {
}
$(document).ready(function(){
});
Maybe there are more, what are the differences?
Your notation is mainly jQuery (atleast the ones with $)
This is shorthand for a DOM ready function, equivalent to the bottom one
This is a self executing function with the parameter specified in the trailing ()
This is a DOM ready function $(document).ready(function() {}); atleast, the function above it is simply a function.
so these indeed are a few different ways to execute javascript code, some of them are library dependent (using jQuery) others are done specifically because of differences in scope.
the first block:
$(function() {
...
});
is utilizing the js library jQuery that uses the namespace '$' what you are doing here is calling the jQuery '$' function passing in the first parameter of another anonymous function... this is a shorthand way to call $(document).ready(function(){});... both of those statements wait for the DOM to complete loading (via the onload event) before interpreting the javascript inside
the second block:
(function() {
})();
is a procedure called an (IIFE) Immediately-Invoked Function Expression... which in essense is defining an anonymous function and calling it immediately.
the third block:
function() {
}
$(document).ready(function(){
});
represents two things... the first function declared actually should have been named something like function myFunction(){...} and thus could be called later myFunction(parameters);
and finally $(document).ready(function(){}); is the javascript library jQuery's way of saying grab the 'document' element of the dom, and attach an event listen to it looking for the onload event, when that event is triggered execution the function passed as a parameter...
I need to write a function:
function doTestConnCall(param1, param2, callbackfun)
param1 & param2 are parameters which I have used inside the function.
The 3rd parameter - callbackfun is a function which to be called after finishing doTestConnCall
How to achieve this?
Is it possible to pass 2 callbacks inside a single method. Say doTestConnCall(param1,callback1,callback2)
Think I am missing some basics. Could any one lead me
You can do something like this:
callbackfun(argument1, argument2);
or:
callbackfun.apply(this, [ argument1, argument2 ]);
or:
callbackfun.call(this, argument1, argument2);
The same can be done with multiple callbacks. For example:
callback1.call(this);
callback2.call(this);
See: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply
And: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/call
Functions in JS are top level constructs. That means function hello() {} is the same as var hello = function() {};. So if you want to pass hello to the function above, you can just call doTestConnCall(param1, param2, hello) after you have defined hello() using either method above.
This is how you achieve it.
It is possible to pass what ever you want to as a method parameter.
function doTestConnCall(param1, param2, callbackfun){
DO YOUR LOGIC
callbackfun() // CALL YOUR CALLBACK
}
Call any callback whenever appropriate in the function you are writing--in the case you described, after it completes its core work.
Yes, of course. Call them one after another.
function multipleCallbacks(arg, arg, callback1, callback2) {
// Do some stuff
// Do error checking in the real world if you need to be tolerant
callback1();
callback2();
}
How do I make the myFunction visibile for the in-line function in .ready() event?
$(document).ready(function() {
...stuffs...
myFunction(par1, par2, anotherFucntion_callback);
}
);
function anotherFunction_callback(data) {
..stuffs..
}
I didn't quite catch your question. Do you mean that you want to pass "myFunction_callback(data)" as the last argument in your:
myFunction(par1, par2, anotherFunction_callback);
, including that "data" parameter?
In that case the solution is pretty standard, write this before that one:
var temp = function() { anotherFunction_callback(data) };
an alternative syntax is:
function temp() { myFunction_callback(data) };
// even though this looks just like a free function,
// you still define it inside the ready(function())
// that's why I call it "alternative". They are equivalent.
In general, if you want to pass a function with 1 or more arguments to another function, you use that format. Here, we basically create a new no-argument function that calls another. The new function has access to the "data" variable. It's called "closure", you may want to read more on that.
Of course, if the callback require no argument, you can just use the original function name.
I hope this helps.
ps: You can even inline the function declaration, making it anonymous, like so:
myFunction(par1, par2, function() { myFunction_callback(data) });
Notice that the
$(document).ready(function() {});
looks pretty much just like that.
You use the actual name of the function, i.e. myFunction_callback instead of myFunction or anotherFucntion_callback.