extract parameters from callback outside of the callback - javascript

How can I extract the arguments (a, b) of a callback-function and add another
parameter (c) to the function-call?
function mycallback(a, b, c) {
// do stuff with a, b, c
}
function perform(callback) {
// I need to extract a and b here and add c:
// ???
//callback.apply(???);
}
perform( function() { mycallback(1, 2) } );

The only way I can think of is to pass the parameters to perform itself and then let it pass them along to the callback:
function perform(callback) {
var args = Array.prototype.slice.apply(arguments).splice(1);
// use args... add c with args.push(c)...
callback.apply(this, args);
}
perform(mycallback, 1, 2);

Related

input function into other function

i'm trying to input a function into another function and then running it.
I have a function.
function example_function() {
document.print('example')
and I would like to input into another function to have it executed N times.
function do_n_times(function, times) {
for (var i = times; i < times; i++) {
do(function)
}
}
Is there a way to do this, and if so. Can you also do custom inputs?
function do_n_times_with_this_input(function, times, input) {
for (var i = times; i < times; i++) {
do(function(input))
}
}
You can absolutely do this! JavaScript has what's called first-class functions, which means they can be passed around just like any other variable. The syntax for that looks like this:
function example_function() {
console.log('example')
}
function do_n_times(func, times) {
for (var i = 0; i < times; i++) {
func();
}
}
do_n_times(example_function, 5);
Yes, you can do what you describe. In JavaScript, you can call any variable as a function by appending () at the end:
function f1() {
console.log("f1 called")
}
const f2 = () => console.log("f2 called");
const nonFn = 42;
f1();
f2();
try {
nonFn();
} catch (e) {
console.log("Error because nonFn is not a function")
}
You can further pass functions in any way you want:
function f1() {
console.log("f1 called")
}
const f2 = () => console.log("f2 called");
function caller(fn) {
fn();
}
caller(f1);
caller(f2);
caller(() => console.log("directly defined arrow function called"));
caller(function() { console.log("directly defined normal function called"); });
Which also means that you can pass any input you want as well:
function f1(input) {
console.log("f1 called with", input)
}
const f2 = input => console.log("f2 called with", input);
function caller(fn, input) {
fn(input);
}
caller(f1, "foo");
caller(f2, "bar");
caller(
input => console.log("directly defined arrow function called with", input),
"baz"
);
caller(
function(input) { console.log("directly defined normal function called with", input); },
"quux"
);
This is the basic stuff, you can have more control over how you execute a function by using Function#call and Function#apply. In both cases that allows you to execute a function and change its context
function f() {
console.log("f called with context:", this);
}
function caller(fn) {
const newContext = {foo: "hello"}
fn.call(newContext);
}
function applier(fn) {
const newContext = {bar: "world"}
fn.apply(newContext);
}
caller(f);
applier(f);
You can also pass arguments in both cases. The difference between .call() and .apply() is in what form you pass them. And if you don't care about the context (the function is not using this) then you can just use null as the argument for that:
function f(a, b, c) {
console.log(
"f called with arguments",
"\n\ta:", a,
"\n\tb:", b,
"\n\tc:", c
);
}
function caller(fn, a, b, c) {
fn.call(null, a, b, c);
}
function applier(fn, a, b, c) {
fn.apply(null, [a, b, c]);
}
caller(f, "passed", "directly", "into");
applier(f, "passed", "as", "array");
The difference seems negligible but here is a real good use-case for .apply - you can supply infinite arguments to a function:
function f(...args) {
console.log(
"f called with arguments:", args
);
}
function applier(fn) {
const argumentsForFunction = Array.prototype.slice.call(arguments, 1);
fn.apply(null, argumentsForFunction);
}
applier(f, "one");
applier(f, "alpha", "beta", "gamma");
applier(f, "a", "b", "c", "d", "e", "f", "g");
Notice how Array#slice was called with the arguments object in order to exclude the first item (the function) and take the rest.
You can get quite a lot of control over how a function is executed. using these.
A final option is Function#bind - it works a lot like call in that you can change the context and pass arguments but the difference is that it returns a new function that will always use these. This has useful applications - you can permanently set this so you never "loose" it.
Another useful application of the .bind() method is creating called "partially applied function" - this is a function that normally takes multiple parameters but you've permanently set some of them, so the function only waits for the remaining ones or even just for execution:
function f(a, b) {
console.log(
"f called with arguments",
"\n\ta:", a,
"\n\tb:", b
);
}
//null for the context - we don't care for it here
const f1 = f.bind(null, "hello");
f1("world");
f1("my baby");
f1("my honey");
const f2 = f1.bind(null, "my ragtime gal");
f2();

Find which parameters a higher order function contains

I have a function that accepts a function as an argument.
This callback function can receive up to 5 parameters. Any of these can be null at some point.
I tried accessing the arguments property, but it throws this error:
'caller', 'callee', and 'arguments' properties may not be accessed on strict mode.
Is it possible to find which arguments this function received? So i don't have to pass it all 5 each time?
function bar(callback){
// do some stuff
return callback(first, second, third, fourth, fifth)
}
Some use cases I'm having:
bar((a, b, c) => a + c)
bar((a, b, c, d) => a + c + d)
bar((a, b, c, d, e) => a + b + e)
I'm always calling the callback with 5 arguments, but sometimes, not all of them are being used. And for each one, I'm doing some computation.
Another example:
If I call the function like this:
bar((a, b, c, d, e) => a + b + e)
And my function defined like this:
function bar(callback){
// do some stuff with
return callback(first, second, third, fourth, fifth)
}
There would be no need for me to pass the third and fourth parameters to the callback, because they are null. But since I don't have access to the arguments the callback has received, I'm not being able to do this.
You could use Function.length,
function func1() {}
function func2(a, b) {}
console.log(func1.length);
// expected output: 0
console.log(func2.length);
// expected output: 2
But, I would not advice writing code that relies on this. The callback function could be implemented in different ways that this wouldn't work. Some examples:
function callback(){
console.log(arguments); // could access all parameters but length is 0
}
function callback(...args){
console.log(args); // could access all parameters but length is 0
}
function callback(a,b=0,c,d,e){
console.log(a,b,c,d,e); // could access all parameters but length is 1
// 1, only parameters before the first one with
// a default value is counted
}
A better solution would be not overloading the function with different behaviors depending on what the callback expects, and actually tell what you should "return" to the callback
function bar(callback, n){
if(n===0) // do something
else if(n===1) // do something else
}
Or don't write "overloaded" functions that have multiple behaviors, and actually having multiple functions:
function foo(callback){
// do some sutff
return callback(first, second)
}
function bar(callback){
// do some sutff
return callback(first, second, third, fourth, fifth)
}
EDIT: from your last edit you should need to have something like this
function bar(params, callback) {
const obj = {
a: 1,
b: 2,
c: 3,
d: 4,
e: 5
};
const args = params.map(p => obj[p]);
return callback.apply(this, args);
}
console.log(bar(['a', 'b'], (a, b) => a + b)) //3
console.log(bar(['a', 'd', 'e'], (a, d, e) => a + d + e)) //10
You could take the Function#length property of the function, which returns the number of defined parameters.
function bar(callback) {
console.log(callback.length);
}
bar((a, b) => a + b);
bar(function (a, b, c) { console.log(a, b, c); });

How to pass a function with arguments to a function as argument in javascript? [duplicate]

This question already has answers here:
Passing a function with parameters as a parameter?
(7 answers)
Closed 3 years ago.
I'm new to javascript and I was learning higher-order functions where I learned about passing functions as arguments to other functions. How can I pass a function with arguments to a function?
I want to pass the function's arguments when passing the function as parameter to the main function.
example :
function fubar(a,b,fun(c,d)){
//execute here
}
and not like this
function fubar(a,b,fun()){
fun(a,b)
}
Here's an example, just pass it like a regular argument, no specific syntax is required :)
// define the function argument like a regular argument
function fubar(a, b, fn){
// call that argument like a function
return fn(a, b);
}
// sample function
function add(c, d){
return c + d;
}
// pass the "add" function like a regular argument
let result = fubar(1, 2, add);
console.log(result);
You just need to pass the name of the function as the parameter, just like another variable.
for example :
foobar(5, 10, baz, ham);
function foobar(a, b, fn1, fn2){
...
fn1(); // call the baz function.
res = fn2(a,b); // calls ham func with a and b as parameter
console.log(res)
...
}
function baz(){
console.log("Inside the Baz function ");
}
function ham(s,t){
console.log(s, t);
return s+t;
}
If you're asking how to pass a function that will execute with some pre-determined arguments, you can do so using another function.
For example
const a = 'a'
const b = 'b'
const c = 'c'
const d = 'd'
function fubar(a, b, fn) {
console.info('func:', a, b, fn()) // executing "fn()" here
}
function fun(arg1, arg2) {
console.info('fun:', arg1, arg2)
return 'return value from fun' // just an example so you can see it in fubar()
}
fubar(a, b, () => fun(c, d))
Here, () => fun(c, d) is an self-contained, anonymous arrow function (or "lambda") that when called, will execute fun(c, d).

passing a self function as a callback using closure/function binding

Is it possible to use closure or function binding to pass a self function as an argument for callback from within the function itself?
I used some code to better explain what I'm trying to achieve.
x: function(a, b, c){
if(certain conditions not met){
y(pass function x as argument along with arguments a,b,c for callback);
}
//blah blah
}
y: function(callbackFunc){
//do some stuff
//then execute callback function
callbackFunc();
}
You can define x as a named function, set a flag at if condition to determine whether to pass x or call x to prevent recursive calls to y and x; use Function.prototype.bind() to set this to current or other object, alternate flag at y, call x with y to access original parameters passed to x; optionally pass additional parameters to x.
var obj = {
z: true,
x: function x(a, b, c) {
if (this.z === true) {
this.y(x.bind(this, arguments));
} else {
console.log(arguments, this)
}
//blah blah
},
y: function(callbackFunc) {
//do some stuff
//then execute callback function
if (this.z) {
this.z = false;
// pass additional parameters to `x`
callbackFunc("abc")
};
}
}
obj.x(1, 2, 3);
You can try
x: function(a, b, c){
if(certain conditions not met){
this.y(this.x, a,b,c);
}
//blah blah
}
y: function(callbackFunc,a1,b1,c1){
//do some stuff
//then execute callback function
callbackFunc(a1,b1,c1);
}
I have written a1,b1,c1 just to differenciate, you can use a,b,c

How to bind function arguments without binding this?

In Javascript, how can I bind arguments to a function without binding the this parameter?
For example:
//Example function.
var c = function(a, b, c, callback) {};
//Bind values 1, 2, and 3 to a, b, and c, leave callback unbound.
var b = c.bind(null, 1, 2, 3); //How can I do this without binding scope?
How can I avoid the side-effect of having to bind the function's scope (e.g. setting this = null) as well?
Edit:
Sorry for the confusion. I want to bind arguments, then be able to call the bound function later and have it behave exactly as if I called the original function and passed it the bound arguments:
var x = 'outside object';
var obj = {
x: 'inside object',
c: function(a, b, c, callback) {
console.log(this.x);
}
};
var b = obj.c.bind(null, 1, 2, 3);
//These should both have exact same output.
obj.c(1, 2, 3, function(){});
b(function(){});
//The following works, but I was hoping there was a better way:
var b = obj.c.bind(obj, 1, 2, 3); //Anyway to make it work without typing obj twice?
I'm still new at this, sorry for the confusion.
Thanks!
You can do this, but best to avoid thinking of it as "binding" since that is the term used for setting the "this" value. Perhaps think of it as "wrapping" the arguments into a function?
What you do is create a function that has the desired arguments built into it via closures:
var withWrappedArguments = function(arg1, arg2)
{
return function() { ... do your stuff with arg1 and arg2 ... };
}(actualArg1Value, actualArg2Value);
Hope I got the syntax right there. What it does is create a function called withWrappedArguments() (to be pedantic it is an anonymous function assigned to the variable) that you can call any time any where and will always act with actualArg1Value and actualArg2Value, and anything else you want to put in there. You can also have it accept further arguments at the time of the call if you want. The secret is the parentheses after the final closing brace. These cause the outer function to be immediately executed, with the passed values, and to generate the inner function that can be called later. The passed values are then frozen at the time the function is generated.
This is effectively what bind does, but this way it is explicit that the wrapped arguments are simply closures on local variables, and there is no need to change the behaviour of this.
In ES6, this is easily done using rest parameters in conjunction with the spread operator.
So we can define a function bindArgs that works like bind, except that only arguments are bound, but not the context (this).
Function.prototype.bindArgs =
function (...boundArgs)
{
const targetFunction = this;
return function (...args) { return targetFunction.call(this, ...boundArgs, ...args); };
};
Then, for a specified function foo and an object obj, the statement
return foo.call(obj, 1, 2, 3, 4);
is equivalent to
let bar = foo.bindArgs(1, 2);
return bar.call(obj, 3, 4);
where only the first and second arguments are bound to bar, while the context obj specified in the invocation is used and extra arguments are appended after the bound arguments. The return value is simply forwarded.
In the native bind method the this value in the result function is lost. However, you can easily recode the common shim not to use an argument for the context:
Function.prototype.arg = function() {
if (typeof this !== "function")
throw new TypeError("Function.prototype.arg needs to be called on a function");
var slice = Array.prototype.slice,
args = slice.call(arguments),
fn = this,
partial = function() {
return fn.apply(this, args.concat(slice.call(arguments)));
// ^^^^
};
partial.prototype = Object.create(this.prototype);
return partial;
};
var b = function() {
return c(1,2,3);
};
One more tiny implementation just for fun:
function bindWithoutThis(cb) {
var bindArgs = Array.prototype.slice.call(arguments, 1);
return function () {
var internalArgs = Array.prototype.slice.call(arguments, 0);
var args = Array.prototype.concat(bindArgs, internalArgs);
return cb.apply(this, args);
};
}
How to use:
function onWriteEnd(evt) {}
var myPersonalWriteEnd = bindWithoutThis(onWriteEnd, "some", "data");
It's a bit hard to tell exactly what you ultimately want to do because the example is sort of arbitrary, but you may want to look into partials (or currying): http://jsbin.com/ifoqoj/1/edit
Function.prototype.partial = function(){
var fn = this, args = Array.prototype.slice.call(arguments);
return function(){
var arg = 0;
for ( var i = 0; i < args.length && arg < arguments.length; i++ )
if ( args[i] === undefined )
args[i] = arguments[arg++];
return fn.apply(this, args);
};
};
var c = function(a, b, c, callback) {
console.log( a, b, c, callback )
};
var b = c.partial(1, 2, 3, undefined);
b(function(){})
Link to John Resig's article: http://ejohn.org/blog/partial-functions-in-javascript/
Using LoDash you can use the _.partial function.
const f = function (a, b, c, callback) {}
const pf = _.partial(f, 1, 2, 3) // f has first 3 arguments bound.
pf(function () {}) // callback.
May be you want to bind reference of this in last but your code:-
var c = function(a, b, c, callback) {};
var b = c.bind(null, 1, 2, 3);
Already applied binding for instance this and later you can not change it.
What I will suggest that use reference also as a parameter like this:-
var c = function(a, b, c, callback, ref) {
var self = this ? this : ref;
// Now you can use self just like this in your code
};
var b = c.bind(null, 1, 2, 3),
newRef = this, // or ref whatever you want to apply inside function c()
d = c.bind(callback, newRef);
Use a protagonist!
var geoOpts = {...};
function geoSuccess(user){ // protagonizes for 'user'
return function Success(pos){
if(!pos || !pos.coords || !pos.coords.latitude || !pos.coords.longitude){ throw new Error('Geolocation Error: insufficient data.'); }
var data = {pos.coords: pos.coords, ...};
// now we have a callback we can turn into an object. implementation can use 'this' inside callback
if(user){
user.prototype = data;
user.prototype.watch = watchUser;
thus.User = (new user(data));
console.log('thus.User', thus, thus.User);
}
}
}
function geoError(errorCallback){ // protagonizes for 'errorCallback'
return function(err){
console.log('#DECLINED', err);
errorCallback && errorCallback(err);
}
}
function getUserPos(user, error, opts){
nav.geo.getPos(geoSuccess(user), geoError(error), opts || geoOpts);
}
Basically, the function you want to pass params to becomes a proxy which you can call to pass a variable, and it returns the function you actually want to do stuff.
Hope this helps!
An anonymous user posted this additional info:
Building on what has already been provided in this post -- the most elegant solution I've seen is to Curry your arguments and context:
function Class(a, b, c, d){
console.log('#Class #this', this, a, b, c, d);
}
function Context(name){
console.log('#Context', this, name);
this.name = name;
}
var context1 = new Context('One');
var context2 = new Context('Two');
function curryArguments(fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function bindContext() {
var additional = Array.prototype.slice.call(arguments, 0);
return fn.apply(this, args.concat(additional));
};
}
var bindContext = curryArguments(Class, 'A', 'B');
bindContext.apply(context1, ['C', 'D']);
bindContext.apply(context2, ['Y', 'Z']);
Well for the exemple you gave, this will do
var b= function(callback){
return obj.c(1,2,3, callback);
};
If you want to guarenty enclosure of the parameters :
var b= (function(p1,p2,p3, obj){
var c=obj.c;
return function(callback){
return c.call(obj,p1,p2,p3, callback);
}
})(1,2,3,obj)
But if so you should just stick to your solution:
var b = obj.c.bind(obj, 1, 2, 3);
It's the better way.
Simple like that?
var b = (cb) => obj.c(1,2,3, cb)
b(function(){}) // insidde object
More general solution:
function original(a, b, c) { console.log(a, b, c) }
let tied = (...args) => original(1, 2, ...args)
original(1,2,3) // 1 2 3
tied(5,6,7) // 1 2 5
I'm using this function:
function bindArgs(func, ...boundArgs) {
return function (...args) {
return func(...boundArgs, ...args);
};
}
// use
const deleteGroup = bindArgs(this.props.deleteGroup, "gorupName1");
Why not use a wrapper around the function to save this as mythis ?
function mythis() {
this.name = "mythis";
mythis = this;
function c(a, b) {
this.name = "original";
alert('a=' + a + ' b =' + b + 'this = ' + this.name + ' mythis = ' + mythis.name);
return "ok";
}
return {
c: c
}
};
var retval = mythis().c(0, 1);
jQuery 1.9 brought exactly that feature with the proxy function.
As of jQuery 1.9, when the context is null or undefined the proxied function will be called with the same this object as the proxy was called with. This allows $.proxy() to be used to partially apply the arguments of a function without changing the context.
Example:
$.proxy(this.myFunction,
undefined /* leaving the context empty */,
[precededArg1, precededArg2]);
Jquery use case:
instead:
for(var i = 0;i<3;i++){
$('<input>').appendTo('body').click(function(i){
$(this).val(i); // wont work, because 'this' becomes 'i'
}.bind(i));
}
use this:
for(var i = 0;i<3;i++){
$('<input>').appendTo('body').click(function(e){
var i = this;
$(e.originalEvent.target).val(i);
}.bind(i));
}

Categories