I want to write my own function in JavaScript which takes a callback method as a parameter and executes it after the completion, I don't know how to invoke a method in my method which is passed as an argument. Like Reflection.
example code
function myfunction(param1, callbackfunction)
{
//do processing here
//how to invoke callbackfunction at this point?
}
//this is the function call to myfunction
myfunction("hello", function(){
//call back method implementation here
});
You can just call it as a normal function:
function myfunction(param1, callbackfunction)
{
//do processing here
callbackfunction();
}
The only extra thing is to mention context. If you want to be able to use the this keyword within your callback, you'll have to assign it. This is frequently desirable behaviour. For instance:
function myfunction(param1, callbackfunction)
{
//do processing here
callbackfunction.call(param1);
}
In the callback, you can now access param1 as this. See Function.call.
I too came into same scenario where I have to call the function sent as parameter to another function.
I Tried
mainfunction('callThisFunction');
First Approach
function mainFuntion(functionName)
{
functionName();
}
But ends up in errors. So I tried
Second Approach
functionName.call().
Still no use. So I tried
Third Approach
this[functionName]();
which worked like a champ. So This is to just add one more way of calling. May be there may be problem with my First and Second approaches, but instead googling more and spending time I went for Third Approach.
function myfunction(param1, callbackfunction)
{
//do processing here
callbackfunction(); // or if you want scoped call, callbackfunction.call(scope)
}
object[functionName]();
object: refers to the name of the object.
functionName: is a variable whose value we will use to call a function.
by putting the variable used to refer to the function name inside the [] and the () outside the bracket we can dynamically call the object's function using the variable. Dot notation does not work because it thinks that 'functionName' is the actual name of the function and not the value that 'functionName' holds. This drove me crazy for a little bit, until I came across this site. I am glad stackoverflow.com exists <3
All the examples here seem to show how to declare it, but not how to use it. I think that's also why #Kiran had so many issues.
The trick is to declare the function which uses a callback:
function doThisFirst(someParameter, myCallbackFunction) {
// Do stuff first
alert('Doing stuff...');
// Now call the function passed in
myCallbackFunction(someParameter);
}
The someParameter bit can be omitted if not required.
You can then use the callback as follows:
doThisFirst(1, myOtherFunction1);
doThisFirst(2, myOtherFunction2);
function myOtherFunction1(inputParam) {
alert('myOtherFunction1: ' + inputParam);
}
function myOtherFunction2(inputParam) {
alert('myOtherFunction2: ' + inputParam);
}
Note how the callback function is passed in and declared without quotes or brackets.
If you use doThisFirst(1, 'myOtherFunction1'); it will fail.
If you use doThisFirst(1, myOtherFunction3()); (I know there's no parameter input in this case) then it will call myOtherFunction3 first so you get unintended side effects.
Another way is to declare your function as anonymous function and save it in a variable:
var aFunction = function () {
};
After that you can pass aFunction as argument myfunction and call it normally.
function myfunction(callbackfunction) {
callbackfunction();
}
myfunction(aFunction);
However, as other answers have pointed out, is not necessary, since you can directly use the function name. I will keep the answer as is, because of the discussion that follows in the comments.
I will do something like this
var callbackfunction = function(param1, param2){
console.log(param1 + ' ' + param2)
}
myfunction = function(_function, _params){
_function(_params['firstParam'], _params['secondParam']);
}
Into the main code block, It is possible pass parameters
myfunction(callbackfunction, {firstParam: 'hello', secondParam: 'good bye'});
callbackfunction = () => {}
callbackfunction2(){
}
function myfunction1(callbackfunction) {
callbackfunction();
}
//Exe
myfunction1(callbackfunction);
myfunction1(callbackfunction2.bind(this));
Super basic implementation for my use case based on some excellent answers and resources above:
/** Returns the name of type member in a type-safe manner. **(UNTESTED)** e.g.:
*
* ```typescript
* nameof<Apple>(apple => apple.colour); // Returns 'colour'
* nameof<Apple>(x => x.colour); // Returns 'colour'
* ```
*/
export function nameof<T>(func?: (obj: T) => any): string {
const lambda = ' => ';
const funcStr = func.toString();
const indexOfLambda = funcStr.indexOf(lambda);
const member = funcStr.replace(funcStr.substring(0, indexOfLambda) + '.', '').replace(funcStr.substring(0, indexOfLambda) + lambda, '');
return member;
}
Related
I have a parent function with a single parameter.
I want to use this parameter in the naming of a couple child functions.
Can this be done?
function A(red) {
function redBall() {
stuff
}
function redHat() {
stuff
}
}
This is a more specific example of what I am trying to create.
I would run this function many times, which is why I need the child functions to have unique names based on the parameter provided.
function name(parameter) {
let parameterThis = '"' + parameter + 'This"';
let parameterThat = '"' + parameter + 'That"';
let $button = '$(".button.' + parameter + '")';
function parameterEnter() {
document.getElementById(parameterThis).style.opacity = "1";
document.getElementById(parameterThat).style.display = "block";
}
function parameterLeave() {
document.getElementById(parameterThis).style.opacity = "0";
document.getElementById(parameterThat).style.display = "none";
}
$button.hover(parameterEnter,parameterLeave);
}
TLDR: renaming functions isn't what you really want.
You don't need to make your functions named differently for it to work. That's not how programming is supposed to work. Instead, try to generalize what you're trying to do, so that it can be applied to whatever you pass in. Like, if you need it to do different things in certain cases, add another parameter to the function. Or, if you need unique things to happen for each element, make your function take enter/leave callback functions as arguments. Even if you did programmatically set the function names, you'd have a hard time calling them anyways, because you wouldn't know what they were called.
You could do something like this :
functionA (boolean condition)
{
if (condition)
fonctionB();
else
fonctionC();
}
functionB()
{
// Stuff
}
functionC()
{
// Stuff
}
If what you intend to do is to actually declare a function or another depending of a parameter, I don't think that's possible. But I don't really get why you would want to do that, and perhaps we could help you better if you were more accurate on that matter.
You can try like this, maybe simpler than passing arguments?
var foo = function() {
this.a = function () {
console.log('A function');
}
this.b = function() {
console.log('B function');
}
return this;
}
Then call function you want like this for example
foo().a();
EDIT:
I missunderstood your code, If I understand correctly now, you want to pass purely a string and then call function with such name immediately?
Well, you can do it using eval() but many people advise to stay away from using it, anywhere here it is:
function foo(whatFunction) {
function a() {
console.log('a function');
}
function b() {
console.log('b function')
}
eval(whatFunction)();
}
So then call it foo('b') for example
Seems like the answer to my actual question is no, judging by how everyone has responded.
I'll have to keep thinking on it and find another way to simplify my code.
I need to feed a pipe() handler function a bunch of function names so it can execute them in order, waiting for completion of each as it goes. This is great when those functions don't need parameters passing, but when parameters are needed I can't figure out how to pass them without the function going ahead and invoking itself (caused by the brackets).
For example, this is what I typically pass:
pipeHandler([function1, function2]);
It'll then invoke function1() and function2() before the promise is completed.
Where it gets difficult is when I want to do something like thiss:
pipeHandler([function1('value'), function2]);
That causes function1() to invoke immediately, completely bypassing the promise mechanism.
In case it helps, this is the handler function:
function pipeHandler(requiredFunctions) {
//Execute first required function
var executeFunctions = requiredFunctions[0]();
//Execute each subsequent required function using pipe()
for ( var index = 1; index < requiredFunctions.length; index++ ) {
executeFunctions = executeFunctions.pipe(requiredFunctions[index]);
}
//Execute allDone() using pipe()
executeFunctions = executeFunctions.pipe(allDone);
}
Hope somebody has an idea!
Why not
pipeHandler([function() { function1('value'); }, function2]);
?
This is where anonymous functions shine. If you spend some time working in Javascript, you'll probably encounter the same problem when using setTimeOut at some point.
This can be done concisely using bind. Syntax:
pipeHandler([function1.bind(scope, 'value')]);
Bind returns a partial function application, which is a new function in scope scope, with the fixed first parameter 'value'. It'll work with any number of arguments.
You can use an anonymous function, which can invoke the function1
pipeHandler([function () {;
function1('value')
}, function2]);
if you wanna pass parameters without invoking function you may do it like so :
function add (a, b) {
return a + b;
}
// Outputs: 3
console.log(add(1, 2));
// Outputs: function
console.log(add.bind(this, 1, 2));
and this will return a function
function () { [native code] }
if you wanna invoke it
// this will return 3
console.log(add.bind(this, 1, 2)());
What you're probably looking for is called 'Partial application.'
Depending on which browsers you need to support you may be able to simply use bind.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Partial_Functions
As far as I can tell from reading the question, there is no asynchronicity, just a regular single-threaded sequence of function calls, with the possibility of passing parameters at each call.
If so then you want to use jQuery.Callbacks. Your scenario is precisely what jQuery.Callbacks are for. The documentation says :
The jQuery.Callbacks() function, introduced in version 1.7, returns a
multi-purpose object that provides a powerful way to manage callback
lists. It supports adding, removing, firing, and disabling callbacks.
Having read the documentation for jQuery.Callbacks, it's probably still not obvious how to pass parameters to functions in the list.
The simplest option is to fire the list with an object that can be used by the functions in the list :
function myFunction1(obj) {
console.log(obj.myProperty1);
}
function myFunction2(obj) {
console.log([obj.myProperty1, obj.myProperty2].join());
}
var callbacks = $.Callbacks();
callbacks.add(myFunction1);
callbacks.add(myFunction2);
callbacks.fire({
myProperty1: 'X',
myProperty2: 'Y'
});
A more sophiisicated approach allows you :
to specify parameter(s) for each function as it is added to the list, and
to specify a context for all functions in the list
thus giving you two mechanisms for passing data to the functions and the freedom to specify that data in either a .add() statement or a .fire() statement, or both.
For this, you need the following utility function :
function makeClosure(fn) {
var args = Array.prototype.slice.call(arguments, 1);//seriously clever line - thank you John Resig
return function (context) {
fn.apply(context, args);
}
}
which can be used as follows :
function f1() {
console.log(this.myProperty));
}
function f2(value1, value2) {
console.log(value1 + ', ' + value2);
}
function f3(value1, value2) {
//note the use of `this` as a reference to the context.
console.log(value1 + ', ' + value2 + ', ' + this.myProperty);
}
var callbacks = $.Callbacks();
callbacks.add(makeClosure(f1, 'A1'));
callbacks.add(makeClosure(f2, 'B1', 'B2'));
callbacks.add(makeClosure(f3, 'C1', 'C2'));
callbacks.fire({
myProperty: 'Z'
});
DEMO
jQuery's $.proxy(function, context, value) is particularly helpful in this case since it:
Takes a function and returns a new one that will always have a particular context.
Therefore, not only you can change the context of the function being invoked (you can provide an object instead of this), but you can also pass as many arguments/parameters values as the function receives without invoking it directly:
function fun_w_param(v) {console.info("I'm #1, here's my value: " + v)}
function fun_no_param() {console.info("I'm #2")}
function pipeHandler(f1, f2) {
f2();
console.warn("Handling function1 with a second delay");
setTimeout(function(){f1()}, 1000);
}
// add your value below as a proxy's argument
pipeHandler(
$.proxy(fun_w_param, this, '!!!PROXY!!!'),
fun_no_param
);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Running the above will delay "function1" execution and it will display the value that you provide into the proxy's parameter.
Using arrow methods you can simply do this
pipeHandler([() => function1('value'), function2]
I'm trying to call a js function within another one, but use the argument to specify the function. ie depending on the argument passed, it will call a different function
function toggle(n){
if (sessionStorage['toggle'+n]== 0){
check+n();
}
else
}
So, for example, if the argument 'Balloons' was passed as n, then it will call the function checkBalloons(). "check+n();" is not currently working here. Sorry for my lack of simple js syntax!
If the function is defined in the global scope (browser) you can do:
window["check"+n]();
or some tenants like Node.js you would access it from global object.
global["check"+n]();
if it is a part of some other object then you would do the same.
obj["check"+n]();
Functions and properties defined on an object can be accessed using [] convention as well. i.e obj["propFuncName"] will give you reference to it, so in case of methods you add () to invoke it.
If the function is global, you would do this:
window["check" + n]();
or, you could put your function in an object like so:
myNamespace = {};
myNamespace.checkSomething = function(){ /* ... */ }
// call it like this:
myNamespace["check" + n]();
The answers thus far are correct, but lack explanation.
In JavaScript, you cannot call a function by name when that name is a string. What you can do is retrieve a value from an object by name, and if that value happens to be a function, you can then call it. For example:
var myObject = {};
myObject.myFunction = function() { alert('test!'); };
// Get the property on `myObject` called `myFunction`
var theFunctionLookup = myObject['myFunction'];
// Since that property was a function, you can call it!
theFunctionLookup();
In the browser, functions that are defined in the global scope are attached to the window object. For example, this works:
function myFunction() { alert('test'); }
var theFunctionLookup = window['myFunction'];
theFunctionLookup();
You can shorten the last two lines into one:
function myFunction() { alert('test'); }
// Look up and call the function in one line.
window['myFunction']();
For the same reasons, you can use a dynamically-calculated string to look up functions.
function checkBalloon() {
alert('checking balloon');
}
function toggle(n){
if (sessionStorage['toggle'+n]== 0){
window['check' + n]();
check+n();
}
}
toggle('Balloon');
if you do this way:
if (sessionStorage['toggle'+n]== 0){
window["check" + n]();
}
will work
The documentation of jQuery's hover shows only one method of using the function:
$('.myClass').hover(function () {
console.log('on mouse over');
},
function () {
console.log('on mouse out');
});
However, when you change these to named functions it doesn't work correctly, firing the named functions upon page load (or as soon as you paste it into your console):
function onMouseOver() {
console.log('on mouse over');
}
function onMouseOut()
console.log('on mouse out');
}
$('.myClass').hover(onMouseOver(), onMouseOut());
Changing the last line to:
$('myClass').hover(onMouseOver, onMouseOut);
works as expected (firing on the event), but doesn't allow me to pass anything to the named functions. Is there any way to allow me to pass a variable to the functions?
Yes you need to use anonymous functions for this:
$('myClass').hover(function( e ) {
onMouseOver( param1, param2... );
}, function( e ) {
onMouseOut( param1, param2... );
});
You can pass variables into the named functions by calling it like so:
$('.myClass').hover(function() {
onMouseOver(arg);
}, function() {
onMouseOut(arg);
});
That's the only way to pass arguments, parameters into the named functions from that event.
The hover sugar method isn't really meant for complex scenarios.
In your case it would probably be better to use .on('mouseenter') and on('mouseleave') so that you can pass additional event data to each method, like
$('.myClass').on('mouseenter', {param1: val1}, onMouseOver).on('mouseleave', {param2: val2}, onMouseOut);
Then within your handlers you can access those params like so:
function onMouseOver(e) {
console.log(e.data.param1);
}
function onMouseOut(e) {
console.log(e.data.param2);
}
That's the sort of jQuery way to do it.
This is a problem with function references vs. function invocation. Adding the "()" invokes the function (which in this case you'd be doing at binding time...effectively binding the result of the function rather than the function itself.
To pass arguments the simplest option would be to wrap the named function in an anonymous function (as #antyrat just posted).
And also no, this is not a quirk of hover, this is standard JavaScript (and most any other language that has first class functions).
As several others have noted, you'll have to use currying or binding to pass values to the functions. In the example where you wrote this:
$('.myClass').hover(onMouseOver(), onMouseOut());
you're actually calling the onMouseOver() and onMouseOut() methods immediately on that line, and not when the mouse actually moves over or out of the element; what you wrote is equivalent to writing this:
var mouseOverResult = onMouseOver();
var mouseOutResult = onMouseOut();
$('.myClass').hover(mouseOverResult, mouseOutResult);
That's definitely not what you want.
jQuery can only understand functions that are of the form function(event), so if you want more parameters, or other parameters, you'll have to use currying to get them in there. Currying (named for the math professor who devised the concept) can be thought of as creating a new function where the values you want to pass are 'pre-bound' inside it.
So let's say you have a variable foo that you'd like to pass into your onMouseOver handler, like this:
function onMouseOver(foo) {
...
}
...
var foo = "Hello, World";
$('myClass').hover(...);
To be able to pass that value, you need another function that wraps up that foo and that onMouseOver with a function signature that jQuery can use. You do it like this:
function onMouseOver(foo) {
...
}
...
var foo = "Hello, World";
var curriedOnMouseOver = function(event) {
onMouseOver(foo);
};
$('myClass').hover(curriedOnMouseOver);
As several others have suggested, you can avoid the extra variable declaration by creating the curried closure inside the hover() call:
function onMouseOver(foo) {
...
}
...
var foo = "Hello, World";
$('myClass').hover(function(event) {
onMouseOver(foo);
});
This example above also shows how you would pass the event to your function as well, by simply adding more parameters to it:
function onMouseOver(event, foo, bar) {
...
}
...
var foo = "Hello, World";
var bar = "Goodbye, World";
$('myClass').hover(function(event) {
onMouseOver(event, foo, bar);
});
JavaScript's functions --- or closures --- are incredibly powerful tools, and it would be worth your while to learn some of the things you can do with them, like these examples.
Ok hopefully this come across correctly. I am building a universal javascript function that will build a menu and then also build the functions that each menu item would call. To do this, I need to pass a list of the commands to be called for each option.
So for example:
var thecall = 'alert("hi, this works");';
function myfunction(thecall)
{
//In here I want to excute whatever commands is listed in variable thecall
.....
}
I'm sure doing it this way is completely stupid, but I don't know how else to do this.
Basically, I need my function to perform other functions on a variable basis.
Thanks!!
I made it a bit fancier to show you how you can use it.
var thecall = function(name){alert("hi " + name + ", this works");};
function myFunction(function_ref)
{
function_ref('Mark');
}
myFunction(thecall);
You can execute arbitrary strings of JavaScript using eval(), but that is not the best solution for you here (it's almost never the best solution).
Functions in JavaScript are themselves objects which means you can store multiple references to the same function in multiple variables, or pass function references as parameters, etc. So:
var thecall = function() {
alert("hi, this works");
};
function myfunction(someFunc) {
someFunc(); // call the function that was passed
}
myfunction(thecall); // pass reference to thecall
Note that when passing the reference to the thecall function there are no parentheses, i.e., you say thecall not thecall(): if you said myfunction(thecall()) that would immediately call thecall and pass whatever it returned to myfunction. Without the parentheses it passes a reference to thecall that can then be executed from within myfunction.
In your case where you are talking about a list of menu items where each item should call a particular function you can do something like this:
var menuItems = [];
function addMenuItem(menuText, menuFunction) {
menuItems.push({ "menuText" : menuText, "menuFunction" : menuFunction });
}
function test1() {
// do something
}
addMenuItem("Test 1", test1);
addMenuItem("Test 2", function() { alert("Menu 2"); });
// and to actually call the function associated with a menu item:
menuItems[1].menuFunction();
Notice the second menu item I'm adding has an anonymous function defined right at the point where it is passed as a parameter to addMenuItem().
(Obviously this is an oversimplified example, but I hope you can see how it would work for your real requirement.)
I think your looking for the eval function.
var code= 'alert("hi, this works");';
eval(code);