I have multiple places in my code where i use method references(i.e. just the method name with no arguments) but I need to pass it specefic arguments.
I don't want to insert an anonymous method b.c. it makes the code unreadable.
I've told I can use the .bind method, but I don't know how to use it properly. Can some one elaborate on how to do this.
Here is one example of where I need to to to this.
How do I use bind to add in parameters to ajax_signin?
if(d===0){ajax('arche_model.php',serialize(c)+'&a=signin',ajax_signin,b);}
If you want ajax_signin() to get called with parameters, then you have to make a separate function that you can pass to ajax that calls ajax_signin() with the appropriate parameters. There are a couple ways to do this:
Using an anonymous function:
if(d===0){ajax('arche_model.php',serialize(c)+'&a=signin',function() {ajax_signin("parm1","parm2")},b);}
Creating your own named function:
function mySignIn() {
ajax_signin("parm1","parm2");
}
if(d===0){ajax('arche_model.php',serialize(c)+'&a=signin',mySignIn,b);}
If you want to use .bind() and you are sure you are only running in browsers that support .bind() or you have a shim to make .bind() always work, then you can do something like this:
if(d===0){ajax('arche_model.php',serialize(c)+'&a=signin',ajax_signin.bind(this, "parm1","parm2"),b);}
The .bind() call creates a new function that always has a specific this ptr and always has "parm1" and "parm2" as it's first two parameters.
You should be using partial function application! IE: The following:
// This will call a function using a reference with predefined arguments.
function partial(func, context /*, 0..n args */) {
var args = Array.prototype.slice.call(arguments, 2);
return function() {
var allArguments = args.concat(Array.prototype.slice.call(arguments));
return func.apply(context ? context : this, allArguments);
};
}
The first argument is the function you want to call, the second argument the context, and any arguments after that will be 'pre-loaded' into the function call.
Note: 'Context' is what this will refer to once the function is being executed.
Related
Can someone please explain why we can simply pass a method name to a higher order function and everything works just fine. I know in something like Java I have to call the method words on each element individually. I was told that in Javascript if method signature matches we can simply pass in the name of the function with () and it will work. It is great but I want to know whats going on in the background. Why are we able to do this in javascript ?
function words(str) {
return str.split(" ");
}
var sentences = function(newArr){
return newArr.map(words);
}
In many languages you can pass a reference to a function as an argument to a function. That then allows the host function to use that argument and call that function when appropriate. That's all that is going on in Javascript. When you pass the name of a function without the () after it, you're just passing a reference to the function. That enables the host function to use that function as an argument and call it some time later.
In your specific example, .map() expects you to pass in a function that it will call once for each item in an array. So, you pass the name of a function that will then get called multiple times, once for each item in the array. That function you pass has a bit of a contract that it has to meet. It will be passed three arguments (value, index, array) and it must return a value that will be used to construct a new array.
In Javascript, since there is no argument type checking by the language, it is the developer's responsibility to make sure the arguments of the function you are passing match what the caller of that function will actually pass to it and you have to consult documentation of the calling code itself to know what arguments will be passed to it. You can name the arguments anything you want (that is entirely internal to your function implementation), but the order and the quantity of the arguments is determined by the caller and you must declare your function to match what the caller will provide.
Once thing that confused many in Javascript.
If you pass just a function name, you are passing a reference to the function (something that the host function can call at some later time).
array.map(myFn) // passes a function reference
Or, use an inline function (same outcome):
array.map(function(value, index, arr) {
// code goes here
})
If you put parens at the end of the function name, then the function is executed immediately and the return value of that function execution is what is passed:
array.push(myFn()); // pushes the result of calling myFn()
You are calling the words function repeatedly. You're calling it for each iteration of the map function.
The map function takes a callback which it runs for every iteration. That callback is usually in the form of
function (elementOfNewArr, indexOfNewArr, newArr) { }
Because functions are objects, you can store them on a variable and use that new variable name to call that function, instead of its original one. That's mostly the use of functions as objects. You can toss them around.
let foo = function () { return 'jasper!'; }
let boo = foo;
let ron = boo; // ron() will now return 'jasper!'
So, what you've done is plop in your callback function, though it was defined elsewhere. Since callback functions, like all functions are objects, you can declare that callback function, "saving" it to whatever variable you want and use it in anywhere that you can use it normally.
This is super useful if you have to use the same function in more than one place.
What I believe you are misunderstanding is that functions themselves can be treated the same as other variables in javascript. Consider this example:
var newArr = [1,2,3,4];
newArr.map(function(item){
return item * item;
});
In the above example, a function is passed as an argument to the map() function. Notice that it is described anonymously (no function name given). You can accomplish the exact same thing like this:
var newArr = [1,2,3,4];
function squared(item){
return item * item;
}
newArr.map(squared);
These two examples achieve the same thing, except in the second example, rather than writing the function in place, we define it earlier in the code. If it helps, you can even create the function in the same way as you would any other regular variable:
var squared = function(item){
return item * item;
};
You can pass this function around the same way. If you want to know the difference between defining functions in these ways try var functionName = function() {} vs function functionName() {}
I have a simple function that takes one argument
fn = function(argument) {console.log(argument)}
In setInterval, I want to call the function and pass an external variable:
argument = 1
setInterval(<MY FUNCTION WITH ACCESS TO ARGUMENT>, 1000)
I realize that I could do it with a higher-order function, i.e.
fn = function(argument) {
function () {
console.log(argument)
}
}
argument = 1
setInterval(fn(argument), 1000)
And this does work, but I want to know if it can be done with curry.
I've tried:
fn = _.curry(fn)("foo")
// since the function takes only one argument,
// here it is invoked and no longer can be
// passed as a function to setInterval
fn = _.curry(fn, 2)("foo")
// setting the arity to 2 makes it so the function
// isn't invoked. But setInterval does not pass
// the additional argument and so it never ends
// up getting invoked.
I feel like there is something I'm missing with these curry examples. Am I, or will curry not help here?
Indeed lodash _.curry seems not suitable for your use-case.
But you can use the vanilla JavaScript bind for this:
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.
Syntax
fun.bind(thisArg[, arg1[, arg2[, ...]]])
In your case your code would look like this:
fn = function(argument) {console.log(argument)}
var argument = 1
setInterval(fn.bind(this, argument), 1000)
Lodash alternative
If you really want to do it the lodash way, the equivalant of fn.bind(thisArg, ...args) is _.bind(fn, thisArg, ...args). And if you are not interested in setting the this reference, then you can save one argument with _.partial(fn, ...args):
Creates a function that invokes func with partials prepended to the arguments it receives. This method is like _.bind except it does not alter the this binding.
I have the function
function bind(method, context) {
var args = Array.prototype.slice.call(arguments, 2);
return function() {
var a = args.concat(Array.prototype.slice.call(arguments, 0));
return method.apply(context, a);
}
}
The question was: how this function working and for what it can be used.
I understand that function bind (and return function too) convert array-like arguments into a real array. Method and context is not converted into array (because of 2 index). I can pass extra args in bind function and args into returned function and call method with context as 'this'.
My question is - how it can be used, in what cases. Is method and context - function or objects, or function and object?
This function is usual to produce an event handler function.
When you subscribe to your function to an event, for example, and the function is called the this depends on which call your handler.
If you pass a method of your object instead a function, you want to access your object by this.
The function first 2 arguments are the method (the function you want to bind), the context (the object you want to access on this), and you could add some other fixed arguments, that will be pass to your handler function each time is called.
Then the function return a new function, that you use to subscribe the event listener you need, and this function get all the argument passed by this event and add to the arguments array.
And finally do the magic with apply that allow you to call a function changing the context and passing an arbitrary array as the arguments of the function.
You could use this kind of function not only in event subscribtion, but even in call like array forEach, map and so on.
I know about call and apply in JavaScript, but I'm currently stuck with the following scenario.
I'm using Benchmarkjs, and it has an API defined like this:
.on(eventType, listener)
So I'd do, for instance:
/* Register the onStart callback */
suite.on('start', onStart);
My onStart function will be called so that this === suite.
How can I do so that I can define one of the arguments of onStart?
My code is something like this:
foo = function() {
this.suite.on('start', this.onStart);
}
I'd like my onStart function to have a reference to foo.
Any suggestions?
You can invoke Function.prototype.bind for creating partial applications / curried functions.
.bind() takes the context as first parameter and all following passed in parameters will be used as formal parameters for the bound function invocation.
suite.on( 'start', this.onStart.bind( this, foo ) );
The reference to foo will now be available to onStart() as very first argument.
You can pass this to onStart by wrapping it in a function.
foo = function() {
this.suite.on('start', function(arguments){onStart(arguments, this)});
}
I prefer passing it instead of using bind, since bind isn't supported by IE 8 and lower.
I've built a GUI which passes in a long JS Object as settings for an animation plugin. One of the settings allows for the user to call a function once an animation is complete. Unfortunately, it has to be passed to the JS Object as a string.
... [ 'functioncall()' ] ......
Inside my animation callback, I'm retrieving this string and trying to run it as a function.
First attempt works perfectly, but uses eval...
eval( OS.path_jscall[index].path_jscall[0][i] )
I've setup a more preferred approach like so:
var HookFunction=new Function( OS.path_jscall[index].path_jscall[0][i] );
HookFunction();
Both examples call the functioncall() function perfectly. I'm not sure how to pass (this) to the functioncall() though...
functioncall(obj){ console.log(obj); };
Everything keeps referring to the window. Any ideas? Thanks!
Assuming that HookFunction is the name, you can do either a call() or apply()
HookFunction.call(this,arg1,arg2,...,argN);
//or
HookFunction.apply(this,[arg1,arg2,...,argN]);
the basic difference of the 2 is that call() receives your "this" and an enumerated list of arguments after it, while apply() receives your "this" and an array of arguments
Use .call when calling your function. .call assigns the first parameter to the this variable.
var myFunction = function(arg1, arg2) {
alert(this);
}
myFunction.call(this, "arg1", "arg2");
Using your second example, you could do this:
HookFunction.call(this);