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)
Related
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!)
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)
);
I saw in one tutorial this code snippet:
const myFunction = () => {
return function (caller) {
caller(firstFuctnion());
caller(secondFunction());
};
};
Could you please tell me how it works once I call it like:
myFunction()
How come that I don’t get an error when the caller argument is actually not defined?
On the other hand, if I omit it and write the code like this:
const myFunction = () => {
return function () {
firstFuctnion();
secondFunction();
};
};
those two functions firstFuction() and secondFunction() aren’t executed. So, how exactly does that caller — or however it’s called — work?
For those of you who might want to see the whole functioning code:
const redux = require("redux");
const thunkMiddleware = require("redux-thunk").default;
const axios = require("axios");
const createStore = redux.createStore;
const applyMiddleware = redux.applyMiddleware;
const initialState = {
loading: false,
users: [],
error: "",
};
const FETCH_USERS_REQUEST = "FETCH_USERS_REQUEST";
const FETCH_USERS_SUCCESS = "FETCH_USERS_SUCCESS";
const FETCH_USERS_FAILURE = "FETCH_USERS_FAILURE";
const fetchUsersRequest = () => {
return {
type: FETCH_USERS_REQUEST,
};
};
const fetchUsersSuccess = (users) => {
return {
type: FETCH_USERS_SUCCESS,
payload: users,
};
};
const fetchUsersFailure = (error) => {
return {
type: FETCH_USERS_FAILURE,
payload: error,
};
};
const fetchUsers = () => {
return function (dispatch) {
dispatch(fetchUsersRequest());
axios
.get("https://jsonplaceholder.typicode.com/users")
.then((response) => {
// response.data is the users
const users = response.data.map((user) => user.id);
dispatch(fetchUsersSuccess(users));
})
.catch((error) => {
// error.message is the error message
dispatch(fetchUsersFailure(error.message));
});
};
};
const reducer = (state = initialState, action) => {
console.log(action.type);
switch (action.type) {
case FETCH_USERS_REQUEST:
return {
...state,
loading: true,
};
case FETCH_USERS_SUCCESS:
return {
loading: false,
users: action.payload,
error: "",
};
case FETCH_USERS_FAILURE:
return {
loading: false,
users: [],
error: action.payload,
};
}
};
const store = createStore(reducer, applyMiddleware(thunkMiddleware));
store.subscribe(() => {
console.log(store.getState());
});
store.dispatch(fetchUsers());
I don't get this part. What that dispatch actually does. It is nowhere passed as an argument and it is not defined anywhere what it is. Is it function? I could write whatever there instead.
const fetchUsers = () => {
return function (dispatch) {
dispatch(fetchUsersRequest());
axios
.get("https://jsonplaceholder.typicode.com/users")
.then((response) => {
// response.data is the users
const users = response.data.map((user) => user.id);
dispatch(fetchUsersSuccess(users));
})
.catch((error) => {
// error.message is the error message
dispatch(fetchUsersFailure(error.message));
});
};
};
Let’s consider a simplified version of this code.
Before you added some important context to your question (the fact that myFunction() is actually being used, and how it’s used), I wasn’t quite sure where your confusion was, so this answer starts with a general explanation of callbacks, higher-order functions, and currying.
First, let’s turn the function into an arrow function, so the code is more straight-forward to read.
There are differences between them, but let’s ignore them for now.
Let’s also rename myFunction to outer, so we know which function we’re talking about.
const outer = () => {
return (caller) => {
caller(something);
};
};
outer is a function.
outer() is also a function; that means, the return value of the function outer is, itself, a function.
Since outer is a function that returns a function, this makes outer a higher-order function (HOF) (according to one of the two definitions of HOFs)1.
To be explicit, you can reference the returned function by using another variable:
const inner = outer();
How come that I don’t get an error when the caller argument is actually not defined?
That’s a strange question to ask; when outer() is called, it doesn’t touch on caller yet.
Only calling inner does.
Ask yourself this: why do you not get an error for a and b not being defined here?2
const sum = (a, b) => a + b;
sum;
That’s right: sum isn’t even called!
Just like outer() isn’t even called.
Even one step further, this won’t throw an error even if somethingUndefined isn’t defined anywhere and cannot be set anywhere.
(But you will get linter warnings.)
const someFunction = () => somethingUndefined;
someFunction;
Why do you not get an error here, in this common example of HOFs, despite b not being defined at the point where add(5) is assigned to addFive?
const add = (a) => {
return (b) => a + b;
};
// Or more simply:
// const add = (a) => (b) => a + b;
const addFive = add(5);
console.log(addFive(3)); // Pints 8.
Because the function that needs b, i.e. addFive, has not been called yet.
If you want to force an error due to caller not being defined, you’d have to call the function that actually needs caller defined. The function in question is outer()! You call it, like any other function, with (): outer()(). Now you get a TypeError because caller isn’t a function.
This “double call” is called currying.
The code can also be rewritten like this.
The only difference is that inner is now also accessible in the outer scope where outer is.
See What is the scope of variables in JavaScript?.
const inner = (caller) => {
caller(something);
};
const outer = () => inner;
inner takes the role of the returned function (outer()).
It takes a function as an argument and calls it with something as an argument.
outer is just a function that returns the function inner and nothing else.
It does not call it, it doesn’t touch on caller, it has nothing to do with something.
outer() and inner are identical.
On the other hand, if I omit it and write the code [without caller], those two functions firstFuction() and secondFunction() aren’t executed. So, how exactly does that caller — or however it’s called — work?
First, let’s fix the semantics: firstFuction() and secondFunction() are function calls.
Whether they are functions or not, depends on what firstFuction and secondFunction return.
firstFuction and secondFunction are functions (at least the code implies that they are).
More specifically, consider alert:
alert is a function; you can call it like alert().
alert() is not a function; you cannot call it like alert()().
caller is a callback function.
If you omit caller from the code, then myFunction()() would be the proper call that doesn’t throw an error and simply calls firstFuction and secondFunction.
But the point of the callback is to pass the results of firstFuction and secondFunction to the function caller.
You have to provide that function yourself, e.g. the alert function.
myFunction()(alert) calls the inner function, passing alert to it.
The inner function calls firstFuction and secondFunction and passes their results to the caller, which we specified to be alert.
Could you please tell me how it works once I call it like myFunction()?
Quite simply, nothing happens here.
myFunction returns a function, and that’s it; that function isn’t used further, so it is discarded.
There is a key aspect of higher-order functions that isn’t demonstrated in this code: encapsulating values.
Consider this code:
const add = (a) => {
let count = 0;
return (b) => {
++count;
console.log(`The function to add ${a} to something else has been called ${count} time(s).`);
return a + b
};
};
add and b work similarly to myFunction and caller from before, but now, the outer function also needs an argument, so add() won’t help.
add(5) calls the add function and sets argument a to 5.
Further, add(5)(3) calls the inner, returned function, sets b to 3 and returns 8.
But there’s also some state inside add in the form of a variable called count.
const addFive = add(5);
console.log(addFive(3)); // Prints 8.
// But also logs: "The function to add 5 to something else has been called 1 time(s)."
console.log(addFive(10)); // Prints 15.
// But also logs: "The function to add 5 to something else has been called 2 time(s)."
count is only accessible inside outer (including any function inside of it); it is “encapsulated”.
This is a common way to hide some state that should only be accessible inside a specific function.
a is actually also encapsulated inside add(…); a and count have the same scope and aren’t that different from each other, just that a can be set as an argument when calling add whereas count cannot.
You’ve then added more context, where the call looks more like this:
someOtherFunction(myFunction())
This is different from the situation before where you just wrote the call like myFunction().
Now, the result is not discarded, as it is fed into someOtherFunction (in the original code: store.dispatch).
[caller] is nowhere passed as an argument and it is not defined anywhere.
But now it is the job of someOtherFunction to call myFunction() with the appropriate callback function as an argument.
Now, you don’t pass the function yourself; instead, someOtherFunction does it for you.
Compare this to Where do the parameters in a JavaScript callback function come from?.
If you go back to the sum example function from earlier, then either you pass the arguments yourself:
sum(1, 2);
or some library or framework does it for you:
// Library code
const doTheRightThing = (callback) => callback(1, 2);
// Your code
doTheRightThing(sum);
or a built-in (or host-defined) function does it for you:
[ 1, 2, 3 ].reduce(sum, 0);
It doesn’t matter where these parameters come from or where the function is called from.
But it is called, and it is called with the right arguments somewhere.
1: The two definitions of a higher-order function are
a function that returns a function, or
a function that takes another function as an argument.
outer fits the first definition.
outer() (independently and coincidentally) fits the second definition.
2: Okay, granted, sum() would also not throw an error, but a and b would, nonetheless, be undefined, each. undefined + undefined has semantics that don’t result in an error, but hopefully you get the point: in your original code, myFunction()() would throw an error only because undefined(firstFunction()) isn’t possible. The culprit is the same: caller is undefined.
Functions are treated like any other values, meaning they can be returned from functions.
Calling myFunction will simply return the inner function, which will require a parameter caller to be passed to it when it itself is called.
The inner function will remember any arguments that were passed to it's enclosing function.
An example I use to understand this concept is that of a "multiplier factory" function
const answer = function() {
console.log("The answer is: ");
}
const multiplier = function(factor) {
return function(n){
answer();
console.log( n * factor);
};
}
const twice = multiplier(2);
const triple = multiplier(3);
twice(4); // The answer is: 8
triple(5); // The answer is: 15
In the code above twice and triple are essentially the following
const twice = function(n) {
console.log("The answer is: ");
console.log(n * 2);
}
const triple = function(n) {
console.log("The answer is: ");
console.log(n * 3);
}
twice(4); // The answer is: 8
triple(5); // The answer is: 15
To understand more about these concepts, I suggest reading up on "Higher Order Functions" and "Closures" in Javascript
I think you haven't printed the whole snipet. because, there is no definition to firstFunction() and secondFunction() inside myFunction().
to answer your question, if you want to call the function defined in myFunction(), you need to assign the value to a new variable as it is returning the function. then simple make the function call.
const myFunctionResult = myFunction();
myFunctionResult(someOtherCallerFunction);
but note this will throw an error for the reason mentioned above.
From the book Eloquent Javascript Third Edition, chapter 5.
I can't seem to find this construct 'f()()' in my research and I would like to learn more about it.
I expected to be able to use
noisy(Math.min(3, 2, 1));
but there is no output when doing that.
However, the book example works as intended. But how?
Book example:
function noisy(f) {
return (...args) => {
console.log('calling with', args);
let result = f(...args);
console.log('called with', args + ', returned', result);
return result;
};
}
noisy(Math.min)(3, 2, 1);
f()() invokes a function named f, which presumably returns a function - then, the final () invokes that returned function. Eg
const f = () => {
console.log('first invoke');
return () => console.log('second invoke');
};
const returnedFn = f();
console.log('----');
returnedFn();
f()() is like the above, except that it doesn't store returnedFn in a variable - rather, it just executes the returnedFn immediately.
That's the same sort of thing that noisy is doing - it returns a function, so if you want to call the returned function immediately without storing the returned function anywhere, put another () after calling noisy.
The issue with
noisy(Math.min(3, 2, 1))
is that it's calling Math.min immediately - the interpreter simplifies this to
noisy(1)
before calling noisy, so noisy doesn't see anything about the Math.min or the arguments it was called with. (But the whole point of the noisy function is to log both the input and output of a function)
noisy() takes a function as an argument (it is evident by the line let result = f(...args);). Math.min(3, 2, 1) resolves to a value, not a function which it why it doesn't work when passed into noisy().
All that f()() means is that the function f returns a function, which itself is then executed. It might be easier to understand if we break it down like this:
let g = f();
let result = g();
noisy takes a function as an argument and also returns one. Whenever you try noisy(Math.min(3, 2, 1)); you pass result of Math.min(3, 2, 1) to noisy which is the same as calling noisy(1).
You could also split the confusing instruction into two:
let noisyMin = noisy(Math.min);
noisyMin(3, 2, 1);
Basically you just get a function as a result of noisy(Math.min) and then you call it right away.
f()() is only possible if f() returns a function.
I was looking how filters works in Angularjs and I saw that we need to send 2 sets of parentheses.
$filter('number')(number[, fractionSize])
What does it means and how do we handle it with JavaScript?
It means that the first function ($filter) returns another function and then that returned function is called immediately. For Example:
function add(x){
return function(y){
return x + y;
};
}
var addTwo = add(2);
addTwo(4) === 6; // true
add(3)(4) === 7; // true
$filter('number') returns a function that accepts two arguments, the first being required (a number) and the second one being optional (the fraction size).
It's possible to immediately call the returned function:
$filter('number')('123')
Alternatively, you may keep the returned function for future use:
var numberFilter = $filter('number');
numberFilter('123')
It is the same as this:
var func = $filter('number');
func(number[, fractionSize]);
The $filter() function returns a pointer to another function.
with ES6 or later versions you can do it that way;
const divideBoth = (x) => (y) => {
return x / y;
};
one of the reasons that makes this function type useful is when you have a react.js component that needs have callback function instead of doing it inline way(which is ()=>return value) you can do it the way we did previously. But it is not recommended to use in event callbacks because it gets execute in the first render which might cause issues sometimes