Please help in understanding the below code:
// define our function with the callback argument
function some_function(arg1, arg2, callback) {
// this generates a random number between
// arg1 and arg2
var my_number = Math.ceil(Math.random() * (arg1 - arg2) + arg2);
// then we're done, so we'll call the callback and
// pass our result
callback(my_number);
}
// call the function
some_function(5, 15, function(num) {
// this anonymous function will run when the
// callback is called
console.log("callback called! " + num);
});
In the above code,what is the callback keyword.what is the use of this word.
Even there is no function defined with name callback.
The gap in logic I think you're having a hard time with is anonymous, unnamed functions. Once upon a time, all functions were named. So code was written like this:
function MemberProcessingFunction() {
// etc
}
function AdminProcessingFunction() {
// etc
}
var loginProcessingFunction;
if (usertype == 'BasicMember') {
loginProcessingFunction = MemberProcessingFunction;
}
else if (usertype == 'Admin') {
loginProcessingFunction = AdminProcessingFunction;
}
loginProcessingFunction();
Someone thought "This is dumb. I'm only creating those function names to use them in one place in my code. Let's merge that together."
var loginProcessingFunction;
if (usertype == 'BasicMember') {
loginProcessingFunction = function() {
// etc
};
}
else if (usertype == 'Admin') {
loginProcessingFunction = function() {
// etc
};
}
loginProcessingFunction();
This especially saves a lot of time when you're passing a function to another function as an argument. Often, this is used for "callbacks" - occasions where you want to run certain code, but only after a certain indeterminately-timed function has finished its work.
For your top function, callback is the name of the third argument; it expects this to be a function, and it is provided when the method is called. It's not a language keyword - if you did a "find/replace all" of the word "callback" with "batmanvsuperman", it would still work.
'callback' is a function passed as an argument to the 'some_function' method. It is then called with the 'my_number' argument.
when 'some_function' is actually being called as seen below
// call the function
some_function(5, 15, function(num) {
// this anonymous function will run when the
// callback is called
console.log("callback called! " + num);
});
it receives the whole definition of the third function argument. so basically your 'callback' argument has this value below
function(num) {
// this anonymous function will run when the
// callback is called
console.log("callback called! " + num);
}
To understand better how a function can be passed as an argument to another function, take a look at this answer.
Related
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
Lets imagine that I have some code:
var someString = "";
function do1(){
doA();
doB();
}
function doA(){
// some process that takes time and gets me a value
someString = // the value I got in prior line
function doB(){
//do something with someString;
}
What is the correct way to make sure somestring is defined by doB tries to use it? I think this is a situation that calls for a callback, but I'm not sure how to set it up?
Usually, I have solved this problem like following code by callback parameter. However, I don't know this is correct answer. In my case, it's done well.
var someString = "";
function do1(){
doA(doB);
}
function doA(callback){
// some process that takes time and gets me a value
someString = // the value I got in prior line
callback();
}
function doB(){
//do something with someString;
}
I usually write these such that the function can be called with, or without, the callback function. You can do this by calling the callback function only if typeof callback === 'function'. This allows the function which includes the possibility of a callback to be a bit more general purpose. The call to the callback(), obviously, needs to be from within the callback of whatever asynchronous operation you are performing. In the example below, setTimeout is used as the asynchronous action.
var someString = "";
function do1() {
doA(doB); //Call doA with doB as a callback.
}
function doA(callback) {
setTimeout(function() {
//setTimeout is an example of some asynchronous process that takes time
//Change someString to a value which we "received" in this asynchronous call.
someString = 'Timeout expired';
//Do other processing that is normal for doA here.
//Call the callback function, if one was passed to this function
if (typeof callback === 'function') {
callback();
}
}, 2000);
}
function doB() {
//do something with someString;
console.log(someString);
}
do1();
You can, of course, do this without using a global variable:
function do1() {
doA(doB); //Call doA with doB as a callback.
}
function doA(callback) {
setTimeout(function() {
//setTimeout is an example of some asynchronous process that takes time
//Simulate a result
var result = 'Timeout expired';
//Do other processing that is normal for doA here.
//Call the callback function, if one was passed to this function
if (typeof callback === 'function') {
callback(result);
}
}, 2000);
}
function doB(result) {
console.log(result);
}
do1();
function someFunctionA(callback){
var someString = "modify me";
callback(someString);
}
function someFunctionB(someString){
// do something
}
function main() {
someFunctionA(somefunctionB);
}
Seen and run code below, thought I understand closures... How that 'avatarUrl' in callback argument is received in 'avatar'which is function argument too. I know this is common pattern, just can't get it yet
var GitHubApi = require('github');
var github = new GitHubApi({
version: '3.0.0'
});
var getUserAvataWithCallback = function(user, callback) {
github.search.users({q: user}, function(err,res) {
if (err) { callback(err, null);}
else {
var avatarUrl = res.items[0].avatar_url;
callback(null, avatarUrl);
}
});
};
getUserAvataWithCallback('irom77', function(err,avatar) {
console.log('got url with callback pattern', avatar);
})
So, callbacks are an underlying and integral concept in javascript, so it is important that you understand a few concepts. Look at this example:
// This is the function definition for "foo"
//here the callback argument refers to
//the second argument in the function call at
//the bottom which is a function
var foo = function(arg, callback) {
if(arg%2 != 0)
callback("arg is odd", arg)
else
callback(null, arg)
}
//Function call to foo
foo(2, function(err, num) {
if(err)
console.log(err)
else
console.log(num)
}
So, in the example above, you can think of the function call as a call with two parameters, the integer 2 and a function.
In the function definition:
The integer is referred to as "arg" and the function is referred to as "callback".
When callback("arg is odd", arg) is executed, the function is called with:
err = "arg is odd"
num = arg
When callback(null, arg) is executed, the function is called with:
err = null
num = arg
The important thing to remember here is that in javascript, functions can be passed as arguments to other functions. Do some further reading here.
The name of the argument passed to a function does not need to be the name of the argument in the definition of the function, the argument in the definition is the name of the variable that will be initialized inside the scope of given function. The argument declaration will receive the value passed at the second position of the function call (as per the code you've provided) and you will be able to access it inside the scope with that name. You can:
function foo(arg1, arg2) {
console.log(arg1, arg2);
}
foo(true, true); // will output true, true
foo(0, 1); //will output 0, 1
foo('shikaka', 1); //will output "shikaka", 1
var bar = "shikaka";
foo(bar, "shikaka"); //will output "shikaka", "shikaka"
function abc(arg1,arg2, callback){
console.log(arg1 + arg2) // I am doing something really interesting
if(callback){
callback(arg1+ arg2)
}
}
function add(){
console.log("from call back " + arguments[0])
}
var a =10;
abc(1,2, add)
this works fine, but if we need to send some additional arguments to the call back, what should we do??
Here, Apart from (arg1+ arg2) I need some other arguments to be set from the caller of abc to the callback
And, what is the difference between abc(1,2,add) and abc(1,2,add()) ??
Thanks :)
abc(1,2,add) => Giving the function argument as "function type". This is like giving a pointer to the function for later invoking it.
abc(1,2,add()) => Calling the add() function and giving its return value as argument.
Do you need that the callback support more than an argument? Since JavaScript is a dynamic language, just call the same callback function with more arguments:
callback(1,2,3,4)
callback(1,2,3,4,5)
callback(1,2,3,4,5,6).
JavaScript isn't strict with function signatures: functions have as many arguments as the caller gives to them.
For example, if you've a callback function like this:
function(a, b) {
}
And later you call it this way:
function("hello"); // Where's the second argument??
JavaScript won't complain. Simply b will be undefined.
the difference between add and add():
add is a function and add() is the return value of the function.
if you want to get more arguments of the function. use the arguments object
every function has an arguments object
arguments[0] == 1 arguments[1] == 2 arguments[2] == add.
You can call your callback with parameters from your original function and you can also provide the parameters for the callback inside your function call:
function f1 (args, callback, params) {
callback.apply(this, params); // Params needs to be an array
callback.apply(this, [args]); // This would call callback with 1 param - args
callback.call(this, args); // This is the same as the line above
}
function f2 () {
for (item in arguments) {
console.log(item);
}
}
f1('arg', f2, [1, 2, 3]);
If you call your function with a function call inside the parameters then it would immediately evaluate and it would not be executed as a callback.
The difference between abc(1,2,add) and abc(1,2,add()) is that in the second case, it's not abc that calls add. The consequence is that add executes much sooner than expected and without any arguments.
The usual way to pass extra parameters to a callback is to create an anonymous function that closes over the parameters:
var a=10;
var b=20;
abc(a, b, function(text){
add(a, b);
console.log(text); //logs "abc"
});
I was wondering whether this is legal to do. Could I have something like:
function funct(a, foo(x)) {
...
}
where a is an array and x is an integer argument for another function called foo?
(The idea is to have one function that uses a for loop on the array, and calls that function in the params for every element in the array. The idea is so call this on different functions so elements of two arrays are multiplied and then the sums are added together. For example A[0] * B[0] + A[1] * B[1].)
I think this is what you meant.
funct("z", function (x) { return x; });
function funct(a, foo){
foo(a) // this will return a
}
This is not the way to declare a function with another function as one of it's parameters. This is:
function foodemo(value){
return 'hello '+ value;
}
function funct(a, foo) {
alert(foo(a));
}
//call funct
funct('world!', foodemo); //=> 'hello world!'
So, the second parameter of funct is a reference to another function (in this case foodemo). Once the function is called, it executes that other function (in this case using the first parameter as input for it).
The parameters in a function declaration are just labels. It is the function body that gives them meaning. In this example funct will fail if the second parameter wasn't provided. So checking for that could look like:
function funct(a, foo) {
if (a && foo && typeof a === 'string' && typeof foo === 'function'){
alert(foo(a));
} else {
return false;
}
}
Due to the nature of JS, you can use a direct function call as parameter within a function call (with the right function definition):
function funct2(foo){
alert(foo);
}
funct2(foodemo('world!')); //=> 'hello world!'
If you want to pass a function, just reference it by name without the parentheses:
function funct(a, foo) {
...
}
But sometimes you might want to pass a function with arguments included, but not have it called until the callback is invoked. To do this, when calling it, just wrap it in an anonymous function, like this:
funct(a, function(){foo(x)});
If you prefer, you could also use the apply function and have a third parameter that is an array of the arguments, like such:
function myFunc(myArray, callback, args)
{
//do stuff with myArray
//...
//execute callback when finished
callback.apply(this, args);
}
function eat(food1, food2)
{
alert("I like to eat " + food1 + " and " + food2 );
}
//will alert "I like to eat pickles and peanut butter"
myFunc([], eat, ["pickles", "peanut butter"]);
And what would you like it to achieve? It seems you mixed up a function declaration with a function call.
If you want to pass another calls result to a function just write funct(some_array, foo(x)). If you want to pass another function itself, then write funct(some_array, foo). You can even pass a so-called anonymous function funct(some_array, function(x) { ... }).
I would rather suggest to create variable like below:
var deleteAction = function () { removeABC(); };
and pass it as an argument like below:
removeETC(deleteAction);
in removeETC method execute this like below:
function removeETC(delAction){ delAction(); }
What you have mentioned is legal. Here, foo(X) will get called and its returned value will be served as a parameter to the funct() method
In fact, seems like a bit complicated, is not.
get method as a parameter:
function JS_method(_callBack) {
_callBack("called");
}
You can give as a parameter method:
JS_method(function (d) {
//Finally this will work.
alert(d)
});