Javascript - Pass variable parameters to Function - javascript

I am looking to be able to create two functions, BaseFunction and CallbackFunction where BaseFunction takes in a variable set of parameters as such:
BaseFunction(arg1, arg2, ....)
{
//Call the Callback function here
}
and callback function receives the same parameters back:
CallbackFunction(value, arg1, arg2, ...)
{
}
How can I pass the parameters from the base function to the callback function?

Use apply to call a function with an array of parameters.
BaseFunction(arg1, arg2, ....)
{
// converts arguments to real array
var args = Array.prototype.slice.call(arguments);
var value = 2; // the "value" param of callback
args.unshift(value); // add value to the array with the others
CallbackFunction.apply(null, args); // call the function
}
DEMO: http://jsfiddle.net/pYUfG/
For more info on the arguments value, look at mozilla's docs.

to pass arbitrary number of arguments:
function BaseFunction() {
CallbackFunction.apply( {}, Array.prototype.slice.call( arguments ) );
}

This kind of does the trick:
BaseFunction(arg1, arg2, ....)
{
CallbackFunction(value, arguments);
}
However CallbackFunction needs to accept array:
CallbackFunction(value, argsArray)
{
//...
}

Related

Send function parameters as arguments to another function js [duplicate]

Here are two callback function:
function callback_a(){
alert('a');
}
function callback_b(p){
alert('b says'+ p)'
}
If I want use callback_a
function test(callback){
if(condition){
callback();
}
}
test(callback_a);
But the function test isn't applicable to callback_b, So how to implement a common function that you can passing some callbacks function with multiple possible parameter lists.
There are three options:
The easiest way is to use spread operator:
function test(callback, ...callback_args) {
callback(...callback_args);
}
in this case the invocation of test for function callback_b would be like this:
test(callback_b,"b")
The second way is using arguments which are scoped to any function in JavaScript:
function test(callback) {
callback.apply(null, arguments.slice(1));
}
the invocation of test for function callback_b would be the same:
test(callback_b,"b")
Another options is to use partially applied functions. In this case you should define b_callback like this (ES6 syntax):
let callback_b = (p) => () => void{
alert('b says'+ p)'
}
or without ES6:
function callback_b(p) {
return function(){
alert('b says'+ p)'
}
}
and invoke it like this:
test(callback_b("b"))
There is a special object called arguments that gets created when a function is invoked. It's an array-like object that represents the arguments passed in to a function:
It can be used like this:
test();
// no arguments passed, but it still gets created:
// arguments.length = 0
// arguments >> []
test(a);
// ONE argument passed:
// arguments.length = 1
// arguments >> [a]
test(a,b,c,d);
// FOUR arguments passed:
// arguments.length = 4
// arguments >> [a,b,c,d]
Knowing this, one can call a callback with the rest of the arguments passed in from the parent function using apply like this:
function test(callback) {
callback.apply(null, Array.prototype.slice.call(arguments, 1));
}
// arguments passed into test are available in the function scope when
// .slice is used here to only pass the portion of the arguments
// array relevant to the callback (i.e. any arguments minus the
// first argument which is the callback itself.)
//
// N.B. The arguments object isn't an array but an array like object so
// .slice isn't available on it directly, hence .call was used here)
Might be worth reading up on:
The arguments object
Function.prototype.apply, Function.prototype.call and Function.prototype.bind as they are way to bind a context and arguments to a function (i.e. they'll work with the arguments object to call a function where you may not know how many arguments will be passed)
So how to implement a common function that you can passing some callbacks function with multiple possible parameter lists.
Basically, you don't. The function receiving the callback is in charge of what the callback receives as arguments. When you call Array#forEach, it's Array#forEach that decides what arguments your callback gets. Similarly, String#replace defines what it will call its callback with.
Your job is to say what test will do, what it will call its callback with. Then it's the job of the person using test to write their callback appropriately. For instance: You might document test as calling the callback with no arguments. If the caller wants to use callback_b, then it's up to them to handle the fact that callback_b expects a parameter. There are several ways they can do that:
The could wrap it in another function:
test(function() {
callback_b("appropriate value here");
});
...or use Function#bind
test(callback_b.bind(null, "appropriate value here"));
...but it's their problem, not yours.
Side note: If they pass you callback_b and you call it without any arguments, you won't get an error. JavaScript allows you to call a function with fewer arguments than it expects, or more. How the function handles that is up to the author of the function.
You can pass an anonymous function as the callback that will itself return your desired callback function with parameters.
test(function() { return callback_b(' how are you'); });
see this working snippet that will first use callback_a, then callback_b (with parameter) as the callback:
function callback_a(){
alert('a');
}
function callback_b(p){
alert('b says'+ p);
}
function test(callback){
if(true){
callback();
}
}
test(callback_a);
test(function() { return callback_b(' how are you'); });
You can pass the parameter while calling the callback
function test(callback){
if(condition){
callback();
}
else if(other condition){
callback("b");
}
}
test(callback_b);
You can write your callback function like
function callback_a_b(){
if(arguments.length){
var arg = [].slice.call(arguments);
alert('b says'+ arg[0])
}
else{
alert('a');
}
}
You can pass array of parameters as second param of test function or in ES6 use spread operator read more here
function test(callback, params){
if(condition){
if (params === undefined){
callback();
} else {
callback.apply(null, params); //params must be array
//ES6: callback(...params);
}
}
}
test(callback_a);
test(callback_b, [" whatever"]);
I've just checked in my browser (ffox 51.0.1) that the following works:
function test(callback,other_args){if(condition){callback(other_args);}}
results:
condition=true
test(callback_a)
=> shows the alert with 'a'
condition=false
test(callback_a)
=> doesn't show anything
condition=true
test(callback_b,"pepe")
=> shows the alert with 'b sayspepe'
condition=false
test(callback_b,"pepe")
=> doesn't show anything

Get arguments from an argument translated as a function

I have a function like this:
function MyFunction(argument) {
argument()
}
Is there a way to change argument function's arguments?
Example:
MyFunction(function(e) { // e is argument function's argument
// I want to change e using MyFunction function
})
Like...
function MyFunction(argument) {
argument.arguments = "new value"
// but it returns null...
}
You can use bind
Something like:
argument.bind(this, arg1, arg2, arg3, ..., argn)()
Here you can read full documentation:
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind
//function to call
var logger = function(text){console.log(text)}
logger("hello world");
// You want to overwrite the param with a new one
logger.bind(this, "overwritten parameter")("hello world");

Use function declaration passed as an argument

I am trying to create a stub definition that the code below could use:
func.calc({
'divide': function(num1, num2) {
// do something
},
'add': function(num1, num2, num3) {
// do something
}
});
So far, I've been having trouble getting the parameters passed to the functions in the second argument. Here's what I've been trying to do:
var func = {
calc: function(operationsArray) {
if (div) {
operationsArray[0](args); /* get args */
}
else (add) {
operationsArray[1](args); /* get args */
}
}
}
Is it possible to get the whole function definition (with parameters and implementation) when it is passed as a parameter like in the first snippet?
You're declaring func.temp as method that accepts an Array as second argument. On the other hand, you call the method with an Object as the second argument.
JavaScript specification tells us that field order is not guaranteed:
4.3.3 Object
An object is a member of the type Object. It is an unordered collection of properties each of which contains a primitive value, object, or function. A function stored in a property of an object is called a method.
meaning you shouldn't access in_func & in_func2 using location index (i.e. [0]).
You should either call the function with an array like this:
func.temp(mainArg, [
function(arg1, arg2) {
// do something
},
function(arg1, arg2, arg3) {
// do something
}
]);
OR, implement the function so that it uses explicit names:
var func = {
temp: function(arg1, func_obj) {
// do something with arg1
if (trigger1) {
func_obj.in_func(/* get params */);
}
else (trigger2) {
func_obj.in_func2(/* get params */);
}
}
}

Modifying callback function's argument(s) before calling them

I have a custom object that implements a function that'll be executed later. Here's how someone would call it:
customObject.onSomething(function(e) {
// do something with e
console.log('foobar');
});
Here's how onSomething is getting created:
var CustomObject = function() {
this.onSomething = function(callback) {
// If the user passes in parameter(s), how can I modify them before calling?
callback.apply(this);
}
}
How can I modify the argument(s) the user passed in before performing apply or call on the function?
apply takes a second parameter which is a list of arguments to pass to the function. call does the same, except it passes its own argument-list (everything after the first parameter which is used as this).
So, if you know which parameters you expect, you can just add them to the invoking function as the second parameter to apply (or as a list of parameters to call):
this.onSomething = function(arg1, arg2) {
// reverse the first and second arguments
callback.apply(this, [arg2, arg1]);
// equivalent:
callback.call(this, arg2, arg1);
};
If you don't know what kind of arguments to expect, but you still want to do something with them, you can do so with the builtin arguments pseudo-array which holds the arguments given to the current function (even when you don't declare them explicitly).
You can use this to invoke the callback with the same arguments given to the invoking function, or some transformation of them; e.g.:
this.onSomething = function() {
// call callback with the same arguments we got
callback.apply(this, arguments);
// or, make some changes
var newArgs = ["extra argument", arguments[1], arguments[0]];
callback.apply(this, newArgs);
};
Sounds like what you're asking for is fairly simple, see below:
var CustomObject = function() {
this.onSomething = function(callback, param1, param2) {
param1 += 4;
param2 = 'Something about ' + param2 + ' is different...';
callback.apply(this, [param1, param2]);
}
}

Javascript function called by call and apply can't handle a parameter

Can somebody please explain why the below code returns undefined 2 times ?
var test = function (theArr) {
alert(theArr);
};
test.call(6); //Undefined
var theArgs = new Array();
theArgs[0] = 6;
test.apply(theArgs) //Undefined
The syntax for the JavaScript call method:
fun.call(object, arg1, arg2, ...)
The syntax for the JavaScript apply method:
fun.apply(object, [argsArray])
The main difference is that call() accepts an argument list, while apply() accepts a single array of arguments.
So if you want to call a function which prints something and pass an object scope for it to execute in, you can do:
function printSomething() {
console.log(this);
}
printSomething.apply(new SomeObject(),[]); // empty arguments array
// OR
printSomething.call(new SomeObject()); // no arguments

Categories