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

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]);
}
}

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

Why pass an undefined javascript function parameter?

So I'm learning Javascript and I see this code:
var apple = {//... an object with some properties};
var fruit = apple.someMethod(function (b) {return b.a_property_of_apple});
Where someMethod and a_property_of_apple are valid methods and properties.
My question pertains to the argument, b, of the anonymous function which is not declared or defined anywhere else:
function (b) {return ...
What is going on here? What is b and why is it being used?
Apologies in advance for the basic nature of the question. If someone just wants to drop some focused terms on me to read up on that would be great short of an explanation.
The anonymous function is a callback function being passed to the apple.method() invocation.
apple.method() will invoke that anonymous function at some point during it's execution, ( or pass it to another function ). Whenever it's invoked it will be invoked with an argument that will be available inside the callback. You could call it b, or response, or whatever you want (logical names are best) and be able to use it within the anonymous function.
You should read about Callback functions over at MDN.
EDIT: I will explain the parts to you
var apple = {} This is the definition of an object
var fruit = apple.someMethod(function (b) {return b.a_property_of_apple}); is defining that fruit is equal to the return value of the invocation of apple.someMethod(...)
apple.someMethod(function (b) {return b.a_property_of_apple}); is the invocation of apple.someMethod with function (b) {return b.a_property_of_apple} as the only argument.
The b argument in the anonymous function function (b) {return b.a_property_of_apple} will be passed to it's invocation within the apple.someMethod.
Here is an example snippet.
// define apple
var apple = {
// define method
someMethod: function( callback ) {
var obj = {
a_property_of_apple: "Eat me!" // this will be returned
}
// return the invocation of callback with obj as argument
return callback(obj);
}
}
var fruit = apple.someMethod(function (b) {return b.a_property_of_apple});
console.log(fruit);
EDIT: Ok, going to use something slightly less abstract as an example.
// notice employees being passed to this function
// that is called an argument and is usable inside the function
var orginization = function( employees ) {
// this will take the empoyees argument and assign it to this.employees
// or set this.employees to an empty array if there is no employees argument
this.employees = employees || [ ];
// this is a method ( a method is a function on an object )
// this function takes 3 arguments
this.addEmployee = function( employee ) {
// we use the 3 arguments to push a new object with title, name, and salary
// properties provided by the function arguments
this.employees.push( employee );
}
// this method returns the value stored in this.employees
this.getEmployees = function() {
return this.employees;
}
}
// this is a variable an array of employees only containing 1 employee
// i will use it in the creation of my new orginization
var employess = [
{
title: "CEO",
name: "Enola",
salary: "$$$$$$$"
}
];
// i use the new to create learningInc from originization( employees )
// originization is a constructor function which creates an object
// with methods and properties found on the constructor
var learningInc = new orginization( employess );
// console.log learningInc.getEmployees() an you will see still only the CEO
// works here
console.log( "before newHire: ", learningInc.getEmployees() );
// lets make a newHire
var newHire = {
title: "Peon",
name: "Sadly McFrownFace",
salary: "$"
};
// add the newHire to the employess of learningInc wth out getEmployees() method
learningInc.addEmployee( newHire );
// log the new value of learningInc.getEmployees and you see we now have 2 employees
console.log( "after newHire: ", learningInc.getEmployees() );
Ok now notice this line var learningInc = new orginization( employess );
The employees variable I'm passing to this function as an argument is used in this function var orginization = function( employees ) { ... }.
Hope this help.
My question pertains to the parameter, b, of the anonymous function which is not declared or defined anywhere else: What is going on here?
What is b and why is it being used?
Why you say it is not declared? It is declared right there. Consider this simple JavaScript function:
function doSomething(a, b){
//do something here;
}
In this code, we are creating a function, naming it "doSomething", and declaring two parameters for it a and b. This is how we declare function parameters in JavaScript. Now your example:
function (b) {return ...
is exactly the same, except we didn't give this function a name, which means it is an anonymous function. That's the only difference, but its parameter b is declared right there like any standard function. So there is nothing special going here, it's a standard function parameter and used as such.
There are a couple concepts at work here
Function declarations vs function expressions; you can use function as an operator to define a function, and assign the function to an identifier and pass it around like any normal object
Callbacks; you can pass a function CB into another function A to be called by A (as defined by A)
Passing something without an identifier
Function Declaration
// declare function
function foo(argFoo) {
console.log('foo', argFoo);
}
// invoke function
foo('was declared'); // "foo" "was declared"
Function Expression
// express function
var bar = function (argBar) {
console.log('bar', argBar);
};
// invoke function
bar('was expressed'); // "bar" "was expressed"
Callbacks
function fizz(callback) {
console.log('first I fizz');
callback();
}
function buzz() {
console.log('then I buzz');
}
fizz(buzz);
// "first I fizz"
// "then I buzz"
Passing without an Identifier,
Basically, defining things in-place
// say we have some fn fizzbuzz
function fizzbuzz(foo) {
console.log(foo);
}
// we could pre-define what we want to pass to it
var i = 1;
fizzbuzz(i); // 1
// or we could pass directly
fizzbuzz(1); // 1
// with anything we like
fizzbuzz({some: 'object'}); // {some: "object"}
// even a function
fizzbuzz(function () {}); // function () {}
Maybe if I break down what is happening into more readable code, you can see what is happening.
someMethod is a method that take a function as an argument. This is more easily seen when broken down like below.
It's up to someMethod to determine what they do with that function. In this example, I am executing the function being passed into someMethod and passing it my this context.
var apple = {
name: 'Apple',
someMethod: function(func) {
return func(this);
}
};
function getName (b) {
return b.name;
};
const name = apple.someMethod(getName); // Apple
To your question: b is defined as the first argument to your anonymous function. This is more clearly expressed when the code is broken out above. But you could also express it like this:
const name = apple.someMethod(function(x) { return x.name; }); // Apple
or like this using ES6:
const name = apple.someMethod(x => x.name); // Apple

How to use 2 arguments in a 1-arg javascript function?

I am using the http module in node.js to read from url. The http.get function has this signature:
http.get(options[, callback])
The callback function takes a single argument, res. What can I do if I want to use extra objects/functions inside the callback? I can think of inlining the get call like so:
outerFunction = function(xyz) {
http.get(options, (res) => {
// do stuff with xyz here
xyz(res.blah);
}
});
But if my callback gets long I want to declare it upfront somewhere:
myCallback = function(xyz) {
return function(r) { xyz(r.blah); };
}
And invoke myCallback like so:
outerFunction = function(xyz) {
http.get(options, (res) => {
myCallback(xyz)(res);
});
}
But that seems super clumsy and only to get around the 1-arg callback restriction.
Are there better ways? Thanks!
you can use this code please,because myCallback return a function,then after get the resource,http will pass the res into xyz automatically.
outerFunction = function(xyz) {
http.get(options,myCallback(xyz));
}
You could use the arguments object.
The arguments object is a local variable available within all
functions. You can refer to a function's arguments within the function
by using the arguments object. This object contains an entry for each
argument passed to the function, the first entry's index starting at
0.
Quick example:
function test1234(a){
var args = arguments;
console.log(args); // prints -> 0: "a", 1: "b"
}
test1234('a', 'b');

Javascript - add parameters to a function passed as a parameter

Here is the behaviour I'm looking for:
function one(func){
func(5);
}
function two(arg1, arg2){
console.log(arg1);
console.log(arg2);
}
one(two(3)) //prints 3, 5
Can this behaviour or something similar be accomplished in javascript?
You can always use the bind() function to pass some arguments to your function. It'll create a new function with the first argument - arg1 - equal to the value of 3 in this example:
function one(func){
func(5);
}
function two(arg1, arg2){
console.log(arg1);
console.log(arg2);
}
one(two.bind(null, 3))
You can read more about the bind() function here: MDN - Bind
Some workaround is possible
function one() {
var args = Array.prototype.slice.call(arguments);
var func = args[0];
args.splice(0, 1);
args.push(5);
func.apply(this, args);
}
function two(arg1, arg2) {
console.log(arg1);
console.log(arg2);
}
one(two, 3)
There's a problem with your syntax: function one is expecting its single argument to be a function. Then, below, when you invoke it, you are not passing the function two, but whatever two returns when it's passed a single argument, probably undefined. I don't know what specifically you're trying to accomplish but I'd recommend a little research into closures.
function one(arg){
two(arg, 5); // func here is two so it requires two params...
}
function two(arg1, arg2){
console.log(arg1);
console.log(arg2);
}
one(3)// one expect function so can't execute function here!
as soon as one expects function as argument two(3) should return function.
this condition is required
so in order to achieve it your two function should be
function two(arg1){
console.log(arg1);
return function(arg2) {
console.log(arg2);
};
}
so two(3) function call gets passed as argument to one
so before assigning value to variable engine executes it. And execution of two(3) call logs 3 to console and returns function
function(arg2) {
console.log(arg2);
};
and then engine assigns executed value(returned function) to func variable.
so func parameter of one function now looks like
func = function(arg2) {
console.log(arg2);
};
one calls func with 5 passed in as argument.
so 5 gets logged to console.
Basically you can't specify the parameter in the function or it'll run. You need to specify the function aka one(two), but that obviously wouldn't work.
However if you dynamically create a function you should be able to accomplish the task like so :
function one(func){
func(5);
}
function two(arg1, arg2){
console.log(arg1);
console.log(arg2);
}
one(function(val) { two(3, val) }) //prints 3, 5
well somehow this things work for me
function one(func){
console.log("one is running");
func;
}
function two(args1, args2){
console.log("two is running");
console.log("args1 -> " + args1);
console.log("args2 -> " + args2);
}
//to call it
args1 = 6;
args2 = 12
one(two(args1,args2));

How to pass arguments to a function within an object literal

I have a lot of my code inside an object literal and there are a couple functions where I want to be able to pass the functions arguments for the parameters but I can't figure out how to do that.
Here is an example of my object..
var test = {
button: $('.button'),
init: function() {
test.button.on('click', this.doSomething);
},
doSomething: function(event, param1, param2) {
console.log(param1);
console.log(param2);
}
};
So when the button is clicked and it calls the function doSomething I want to pass in arguments for param1 and param2.
Something similar to this maybe, but this does not work.
test.button.on('click', this.doSomething('click', 'arg1', 'arg2'));
Any ideas, or am I going about this the wrong way?
The jQuery.proxy() function seems to be exactly what you need. Have a good read at the docs and see if they make sense to you. For your specific example,
var test = {
button: $('.button'),
init: function() {
test.button.on('click', $.proxy(this.doSomething, null, 'arg1', 'arg2');
},
doSomething: function(param1, param2, event) {
console.log(param1);
console.log(param2);
}
};
In this example, the parameters to $.proxy are:
this.doSomething - The the function to call
null - The context in which the function will be called. By supplying null, we are saying to use its 'normal' context.
arg1 - The value of param1 formal parameter of the called function
arg2 - The value of param2 formal parameter of the called function
Since the click callback supplied the final parameter (event), that is already provided and doesn't need to be additionally or explicitly declared. The jQuery.proxy() when passed additional parameters passes those at the front of the formal parameter list and any remaining parameters implicitly supplied are passed at the end. So if we a function that looks like:
var f = function(a, b, c) {
console.log(a, b, c);
};
and invoke it through a proxy:
var p = $.proxy(f, null, 2, 3);
p(1);
The value of a, b and c that are logged will be 2,3,1.
This question is also extremely close to this one.
How can I pass arguments to event handlers in jQuery?

Categories