Explain me callback and how its refer to array in code [duplicate] - javascript

This question already has answers here:
Create a custom callback in JavaScript
(11 answers)
Closed 10 months ago.
I dont understand what is callback in this example, espicially line
newArray.push(callback(this[i]));
as i got it (this[i]) is item from Array, but how does CALLBACK refer to code;
const s = [23, 65, 98, 5];
Array.prototype.myMap = function(callback) {
const newArray = [];
for(let i=0;i<this.length;i++){
newArray.push(callback(this[i]));
}
return newArray;
};
const new_s = s.myMap(function(item) {
return item * 2;
});
console.log(new_s);

1. Background concepts
Firstly, this top part is just a function definition where 'callback' is just a parameter that myMap is able to accept. The word 'callback' isn't special and you can use in fact any name, but 'callback' does signal that in your function definition you are asking the caller to supply a function instead of an integer or a string. That is, you could also write something like this:
Array.prototype.myMap = function(param) {
// you can console.log(param) and you would see the parameter in log.
}
And in theory you could then call this function by doing:
s.myMap(1) // the log will show 1
s.myMap("hello") // the log will show "hello"
s.myMap(function() {}) // the log will show [Parameter is a Function]
Secondly, if you name your parameter 'callback', it signals to the caller that they could in fact pass a function into this myMap not just an integer or a string -- so when you write something like this:
Array.prototype.myMap = function(callback_f) {
callback_f(); // <----- call the incoming function passed as a param
}
Then the caller has an idea that they have to supply a function into myMap, either in this way:
s.MyMap(function() {
// do some stuff
})
Or in this way:
function doStuff() {}
s.MyMap(doStuff)
Either way, the parameter callback_f is expected to be a function in this case, and myMap will call and execute this function, regardless of what you pass into it.
2. Answering your question
As you may already know, this is a special function definition because, by doing Array.prototype.myMap you're modifying how all arrays work and all arrays will now gain this function definition myMap.
Secondly, you can call this function by doing s.myMap() if s is any array.
So in your case, the line:
newArray.push(callback(this[i]))
could also be written as:
let result_of_executing_the_callback = callback(this[i])
newArray.push(result_of_executing_the_callback)
which means: first, execute the incoming callback function on this (= current array) at the index i. And what is the incoming callback function? It is the function f that you are passing in when you do s.MyMap(f):
In your case f is this:
function(item) {
return item * 2;
}
picture of f being passed into your function as the parameter 'callback'
(If this is helpful please mark as accepted!)

Related

Calling a function next to another function javascript explanation

Can someone please explain to me this bit of code
return pipe(...fns)(this);
I understand if we didn't have (this), so we returned the reduced functions but (this) confused me.
Full source code here. line 72
https://stackblitz.com/edit/typescript-hv4ntb
It is the same as this:
const pipeFunction = pipe(...fns); // pipe returns a function
const result = pipeFunction(this); // call the returned function with this as argument
return result; // return the result
So if you ever see something like variable(...)(...) you should assume that the variable evaluates to a function that returns a function, like this perhaps:
const variable = (a) => (b) => a + b;
variable(4)(2);
// ==> 6
const partial = variable(8)
[1, 2, 3].map(partial);
// ==> [9, 10, 11]
Javascript is said to have first-class functions (you can read more here on MDN), meaning that you can do with functions what you can do with other types. Storing them into a variable, passing them as argument to other functions, as well as using them as return value from other functions.
The thinking is, just think of functions as values.
In your use-case, a function is just being returned from another function:
function multiply(times) {
return function(number) {
return number * times;
};
}
// as you can see, we are storing the "returned function"
// resulted from calling `multiply` into the `double` variable.
const double = multiply(2);
console.log(
double(5)
);
Now, of course, you could short-circuit the double variable,
and just call the returned function straight away.
function multiply(times) {
return function(number) {
return number * times;
};
}
console.log(
multiply(2)(5)
);

Confusion with how thenable callback works in Promise?

I am new to JS and was learning promises. The code excerpt I want to show is this
promisedFunction.then(data=>console.log(data))
or simply
promisedFunction.then(console.log)
which is equivalent of the former code excerpt. The question is how is that possible to just use then(console.log) instead of then(data=>console.log(data))? Does it mean that we can omit the passed-from-promise data in thenable callback?
data=>console.log(data) is a function that takes a parameter and calls a method with the passed in argument.
If you pass console.log it will execute the same method and still pass the same argument.
In effect you are dropping the extra function call - slightly more abstractly, imagine this:
//some function `f`
const f = x => x + 1;
//different function `g` that just forwards the call to `f`:
const g = x => f(x);
console.log(g(41)); //42
The definition of g is just a function that all it does is call f. Which has exactly the same effect as the f function. So, we can just re-write it as:
//some function `f`
const f = x => x + 1;
//different function `g` that just forwards the call to `f`:
const g = f;
console.log(g(41)); //42
and get exactly the same effect.
In Lambda Calculus, this removal of an essentially empty "wrapper function" is called Eta reduction.
Therefore, yes, both .then(data => console.log(data)) and .then(console.log) do exactly the same, you're performing the same sort of conversion where you're taking out a dummy forwarding function.
However, that's not always an option. For example, if removing the forwarding function will end up calling the target with more parameters, you can get different behaviour. An infamous example is parseInt when used in .map:
const arrayOfString = ["1", "2", "3"];
const arrayOfIntegers1 = arrayOfString.map(parseInt);
const arrayOfIntegers2 = arrayOfString.map(x => parseInt(x));
console.log("arrayOfIntegers1", arrayOfIntegers1);
console.log("arrayOfIntegers2", arrayOfIntegers2);
The issue is that Array#map calls the callback with three parameters - the item, the index, and the array. And parseInt has an optional second parameter - if passed in, it changes how the number is parsed. So you get NaN.
The easiest way to observe this is with console.log:
const arrayOfString = ["1", "2", "3"];
console.log(" --- using just `console.log` as callback ---");
arrayOfString.map(console.log);
console.log(" --- using just `x => console.log(x)` as callback ---");
const arrayOfIntegers2 = arrayOfString.map(x => console.log(x));
So, dropping the intermediate function works as long as it has the same arity as what it will be called with and what the next function will be called with.
data => console.log(data) is a function which takes in data and then calls the function console.log with data as its argument. So, it's a function which gets given data and then it gives that exact same data argument to the console.log function.
As you know console.log is a function, so, you can place console.log instead of your arrow function. This way, it will be called with the data argument and any other arguments natively passed into .then()'s onFulfilled callback (in this case it only gets given the resolved value of the promise).
Take the following example below. bar gets given "hello", which it gives to foo, foo accepts "hello" and returns "hello" back to where it was called, so, bar ends up returning "hello":
const foo = x => x;
const bar = x => foo(x);
console.log(bar("hello"));
In the above example, bar acts somewhat like a middle-man, as all it does is pass x to foo. This middle-step can be removed, by straight-up assigning bar to foo. This way, when we call bar(), we are executing the code defined within the function foo. This is the same idea that allows you to remove the need to explicitly defined your arrow function in .then():
const foo = x => x;
const bar = foo;
console.log(bar("hello"));
This style of coding is known as point-free style code and, in this case, is achieved by eta-reduction.
The return value of promise or the "resolved value" is the input to callback passed in then.
This behavior is not specific to promise but even [1,2,3].forEach(console.log) behaves the same where the 3 arguments of forEach are passed to console log. Thus you get ,
1 0 Array(3) [ 1, 2, 3 ]
2 1 Array(3) [ 1, 2, 3 ]
3 2 Array(3) [ 1, 2, 3 ]
promisedFunction.then expects a function to which will receive the data as a parameter.
in the case of data=>console.log(data) is an array function equal to:
function(data) {
console.log(data);
}
and console.log is also a function which prints in console what receives as a parameter.
That's why console.log works.
If you had:
var print = function(data) {
console.log(data);
}
promisedFunction.then(print) would also work.
See this working example that will resolve after 2 secs:
const doSomething = function(){
return new Promise((resolve, reject) => {
let wait = setTimeout(() => {
resolve('Promise resolved!');
}, 2000)
})
};
var print = function(data) {
console.log(data);
}
doSomething().then(print)

how invoking function as a callback parameter in function proceeded?

I am a beginner to JS world, and I have a question.
when I was studying .forEach() javascript function, I noticed that it takes 2 parameters, the first is a function and the second is the value of This obj and the normal usage like this:
function logArrayElements(element, index, array) {
console.log('a[' + index + '] = ' + element);
}
// Notice that index 2 is skipped since there is no item at
// that position in the array.
[2, 5, , 9].forEach(logArrayElements);
but I noticed also that it can be called also like this:
example num 2 :
[2, 5, , 9].forEach(function(){
console.log(arguments);
});
if .forEach() function takes a callback function as a parameter, how the second example is correct because it takes a function definition not a reference to a function which will be called,
I mean why it accepts a function definition in the second example although it takes a defined function name?
I mean also that forEach need a reference to a function only, so when it loops on each element, it will just add () to the function reference so the function will be called
function definition in javascript returns pointer to that function. You can also go through syntax like
let myFunction = function() { ... } // define function and save it into variable
myFunction() // call the defined function
So passing function by name and passing function definition is same thing
In the second example, the parameter is an anonymous function as compared to first where you defined the function first and used it's reference to pass to .forEach(). So, both are essentially same. You can also write second example like
[2, 5, , 9].forEach(function(element, index, array){
//do something with element
});
If you take a look at Polyfill what it does is it first check if the type of passed callback is a function and if it isn't then it throws an error, otherwise it uses call() to invoke that function so it doesn't matter if its anonymous function or function declaration.
It also checks if number of passed arguments is > 1 or if there is one more parameter after callback and you can access that parameter with this in your callback.
function invoke(callback) {
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
if (arguments.length > 1) var Obj = arguments[1];
var value = 1;
callback.call(Obj, value);
}
invoke(function(e) {
console.log(this)
console.log(1 + e)
}, {foo: 'bar'})
var another = function(e) {
console.log(10 + e)
}
invoke(another);
to reach to the correct answer you have to:
read the correct marked answer comments (the last comment), then read the answer Nenad Vracar as both of them covered my missed approaches, thanks for both of them.

Javascript callback function with parameters [duplicate]

This question already has answers here:
Pass an extra argument to a callback function
(5 answers)
Closed 6 years ago.
This question looks like a duplicate, as the title is nearly replicated. But, my issue seems simpler and I can't find the answer to it.
I have a Javascript function that executes another callback function, it works like this:
<script type='text/javascript'>
firstfunction(callbackfunction);
</script>
where callback function is defined as:
callbackfunction(response) {
if (response=='loggedin'){
// ... do stuff
}}
but I want it to be something like this:
callbackfunction(response, param) {
if (response=='loggedin'){
// ... do stuff with param
}}
My question is, does it work to pass the parameter like this:
<script type='text/javascript'>
firstfunction(callbackfunction(param));
</script>
or am I doing it wrong?
In direct answer to your question, this does not work:
firstfunction(callbackfunction(param));
That will execute callbackfunction immediately and pass the return value from executing it as the argument to firstfunction which is unlikely what you want.
It is unclear from your question whether you should just change firstfunction() to pass two parameters to callbackfunction() when it calls the callback or whether you should make an anonymous function that calls the callback function with arguments.
These two options would look like this:
function firstfunction(callback) {
// code here
callback(arg1, arg2);
}
firstfunction(callbackfunction);
or
function firstfunction(callback) {
// code here
callback();
}
firstfunction(function() {
callbackfunction(xxx, yyy);
});
Use an anonymous function:
function foo( callback ) {
callback();
}
function baz( param ) {
console.log( param );
}
foo( function(){ baz('param') });
Adding parameters when calling a function.
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply
xdaz already answered the simple version.
Here is an example with variable amount of parameters.
function someObject(){
this.callbacks=new Array();
this.addCallback=function(cb){
this.callbacks[this.callbacks.length]=cb
}
this.callCallbacks=function(){
//var arr=arguments; this does not seem to work
//arr[arr.length]="param2";
var arr = new Array();
for(i in arguments){
arr[i]=arguments[i];
}
arr[arr.length]="another param";
i=0;
for(i in this.callbacks){
this.callbacks[i].apply(null,arr);
//this.callbacks[i].apply(this,arr);
//this is a ref to currrent object
}
}
this.callCallbacksSimple=function(arg){
for(i in this.callbacks){
this.callbacks[i](arg,"simple parameter");
}
}
}
function callbackFunction(){
for(i in arguments){
console.log("Received argument: " + arguments[i]);
}
}
var ObjectInstance=new someObject();
ObjectInstance.addCallback(callbackFunction);
ObjectInstance.callCallbacks("call callbacks");
ObjectInstance.callCallbacksSimple("call callbacks");
function is key word, you can't use it as function name.
Let say your function name is foo, then you could do like below:
var param = 'what ever';
foo(function(response) {
callbackfunction(response, param);
});
I think this is what you're looking for.
Lets say you're using jQuery ajax to do something, and you're passing it named callbacks. Here we have an onError callback that you might use to log or handle errors in your application. It conforms to the jQuery Ajax error callback signature, except for an extra parameter that you might have wanted to add at the back
function onError(jqXHR, textStatus, errorThrown, yourOwnVariableThing) {
console.error('Something went wrong with ' + yourOwnVariableThing);
}
this is where your function would be called - but you want an extra parameter
$.ajax("/api/getSomeData/")
.done(onDone)
.fail(onError)
.always(onComplete);
So this is what you can do to add the extra parameter
$.ajax("/api/getSomeData/")
.done(onDone)
.fail(onError.bind(this, arguments[0], arguments[1], arguments[2], 'Moo Moo');
.always(onComplete);
arguments is an array in JavaScript that contains all arguments passed to a function, and so you're just passing those arguments along to the callback.
Arguments
Bind

JavaScript: Get parameters of passed function?

As the title says I'm wondering if it's possible to get the parameters of a passed function. After hours of searching and looking at similar questions I'm still no closer, so I'll attach a simple example rather then what I'm working on - as I'm starting to suspect it's not possible.
Intended global function
function getTransaction(anyMethod)
{
db.transaction
(
function(transaction)
{
anyMethod(transaction);
},
function errorCB(err) {
redirectToLoginWithError("Error processing SQL");
},
function successCB() {
;//alert("Success!");
}
);
}
Functions to be called
function iWork(tx)
{
tx.doSomething();
}
function iDontWork(tx, param1, param2)
{
tx.doSomething(param1, param2);
}
Actual call
// Works fine
getTransaction(iWork);
// The problem
getTransaction(iDontWork, value1, value2);
getTransaction(iDontWork2, value1, value2, ..., valueX);
I've tried several different approaches, but none have proved successful so far. The closest (although not very) have been
getTransaction(function(){iDontWork(value1, value2)}));
This does call the correct function via the getTransaction, but does not pass the parameters correctly: Params (value1, value2) are kept, but the transaction object is lost / undefined. I can see why this does happen, but I cannot see any solution to it. All said, I'm also open to that the getTransaction should be scrapped and re-written somehow. The point is to get a flexible method that scales well.
Simply refactor getTransation to take a function and an array of arguments. Prepend the transaction variable to the argument array and call the function using apply:
function getTransaction(anyMethod, methodArgs) {
var someFunction = anyMethod;
// if no args provided, use an empty array
methodArgs = methodArgs || [];
db.transaction (
function(transaction) {
// transaction is always the first arg; prepend it to the arg list
methodArgs.unshift(transaction);
// call method with argument array
anyMethod.apply(null, methodArgs);
},
// ...
);
}
Simply use it with:
doTransaction(iDontWork, [param1, param2]);
doTransaction(iWork);
EDIT:
As #rambo coder pointed out, you could just use regular arguments (instead of an array of arguments) by slicing arguments:
function getTransaction(anyMethod) {
var someFunction = anyMethod;
db.transaction (
function(transaction) {
var methodArgs = arguments.slice(1);
methodArgs.unshift(transaction);
anyMethod.apply(null, methodArgs);
},
...
This way lets you supply arguments directly to getTransaction, as you do in your example (doTransaction(iDontWork, param1, param2);), instead of putting them in an array.
getTransaction(function (x) {
iDontWork(x, value1, value2);
});
Your getTransaction assumes that its single argument is a function that takes one parameter. You need to create a new function that takes one parameter, but also includes the specific parameter values you want (namely value1 and value2).
The above uses an anonymous function; you could also do it with a named function:
function forwarder(x) {
iDontWork(x, value1, value2);
}
getTransaction(forwarder);
You can do it by creating partial functions:
function iDontWork(param1, param2){
return function(tx) {
tx.doSomething(param1, param2);
}
}
And:
getTransaction(iDontWork(value1, value2));

Categories