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)
);
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!)
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)
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.
function multFn(num){
return function(factor){
return factor*num
}
}
var multFive=multFn(5)
console.log(multFive(2)) // outputs 10
The question?:
How does JS know that when I console.log(multFive(2)) that the 2 should be given to the factor parameter? I know that multFn will return a pointer to the method inside it. But I don't get how the 2 gets assigned to factor.
Calling the first function causes the inner one to be returned to your variable. When you invoke that function, the argument you pass goes to the parameter the second function is expecting.
When you run this first line:
var multFive = multFn(5);
The outer function (multFn) is invoked and 5 is received as num, so the function operates like this:
function multFn(5){
return function(factor){
return factor * 5
}
}
But, that function has a return in it that returns the inner function to your multFive variable, so you wind up with this:
var multFive = function(factor){
return factor * 5;
}
Finally, when you invoke multFive and pass it a 2, the 2 becomes the value of the factor argument that the function is expecting.
console.log(multFive(2));
Causes:
function(2){
return 2 * 5;
}
And, 2 * 5 = 10.
NOTE: I've shown what the functions will execute based on the code you've supplied. There is an advanced concept in JavaScript, called "Closures" that could make it so that the outer function doesn't always have to statically run with 5 as its value. But, for the purposes of your question, that's not relevant.
This is really an example of function currying. Essentially you are returning a function from a function, with some of the needed values already specified during the creation of the returned function.
Calling multFn(5) creates a closure around an anonymous function, and that closure has a reference to num as being 5.
The function that is returned is equivalent to:
function(factor){
var num=5;
return num * factor;
}
and is assigned to the reference multFive.
Inside your console.log(multFive(2)) you are calling that returned function multFive with the argument 2, and you get your result of 2*5=10.
I think your confusion because you think that the result of the assignment:
var multFive = multFn(5);
Will be something like this:
var multFive = function multFn(num) { //num is passed 5
return function(factor) {
return factor * num;
};
}
But that's not the case. It will actually be something like this:
var multFive = function(factor) {
return factor * num;
}
And the value 5 is assigned to the num variable in the closure. On the next line:
console.log(multFive(2));
You're passing 2 directly to the factor parameter and it will be multiplied by the value of num that was stored in the closure earlier.
To see that in action (a proof of that), print out the multFive:
console.log(multFive);
Here is a funny quiz, try to guess the output and then run it to see:
function multFn(num) {
setTimeout(function() {
num = 3;
}, 500);
return function(factor) {
return factor * num;
};
}
var multFive = multFn(5);
console.log(multFive(2)); // outputs 10
setTimeout(function() {
console.log(multFive(2)); //what will the output be here?
}, 1000);
i have a simple function called Range that creates an array of integers based on start, step and end value...
function Range (start, end, step) {
// default step is 1..
if (step === undefined ) step = 1;
// creating an array...
var arr = [], index = 0;
while(start <= end) {
arr[index] = start ;
index += 1;
start += step;
}
// simple function expressions
var getAll = function () {
return arr ;
};
var getOne = function(n) {
return arr[n] ;
};
// returns a unnamed function ..
return function(i) {
if (i === undefined) { return getAll() ;}
else {return getOne(i); }
}; // not an iife
}
so basically Range is a function which returns a unnamed function which again returns a named function expression declared in the function Range.. err.. i dont know.. something like that...
now the below code...
var first10 = Range (1,10) ; // no new ..() here, so no instance should be created.. only Range is called..
var first10Odd = Range(1,20,2) ; // and Range is called again..
alert(first10); // alerts - function(i) { ... }
alert(first10Odd); // alerts- function(i) { ... }
alert(first10()) ; // alerts - 1,2,3,...10
alert(first10Odd()); // alerts - 1,3,5,...19
alert(first10(0)); // alerts - 1
alert(first10Odd(9)); // alerts- 19
why do the alerts alert as specified in the comments??... i think Range is a just a function and not a object constructor and also no instance was created... shouldn't the local variables of function be destroyed as soon as the function is completed??
or is my logic wrong?? what is going on in the above code?? can anyone please explain....
i have made a fiddle of my code here..
sorry for asking this stupid question..
Welcome to the land of closures in Javascript. They can be very powerful and extremely useful once you understand them. But, if your prior experience is with languages that do not have them, they can feel a bit foreign at first.
Some answers/explanation:
Calling Range(x, y) returns a function that can then be called later.
Because that function that is returned is inside another function scope that has variables, a closure is created.
That closure stays alive (even though the outer function has finished executing) because there is a lasting reference to the inner function saved in your variables and that inner function has a reference to the local variables in the outer function. These references keep the closure from being garbage collected (so it stays alive).
That inner function can then reference the variables in the outer function, including the arguments originally passed to it.
This construct allows you to create these custom functions that have arguments pre-built into them.
The notion of this type of closure only exists in some languages. It does not exist in C++, for example.
When the function returned by calling Range(x,y) is itself executed later, it can use any of the variables that were originally in scope to it.
Each call to Range(x,y) causes a new closure to be created.
getAll and getOne are local variables in the outer function that are assigned a function. They access other local variables in the outer function. All of these are in the previously mentioned closure that is created each time Range() is called.
There is lots written about what a closure is (which you can Google and read), but I like to think of it as an execution context that contains everything that was in scope at the time a function is called (including all variables). Each time a function is called, such an execution context it created. Since everything in javascript is garbage collected and will only be freed/destroyed when there are no references left to it, this is true for this execution context too (e.g. closure). As long as something has a reference to it or something in it, then the execution context will stay alive and can be used by any code that might run into that execution context.
Line by line annotation:
// first10 is assigned the anonymous function that the call to Range()
// returned. That anonymous function has access to the original arguments
// passed to the Range(1,10) call and other local variables in that function.
var first10 = Range (1,10) ; // no new ..() here, so no instance should be created.. only Range is called..
// same as the call before, except this also includes the step argument
var first10Odd = Range(1,20,2) ; // and Range is called again..
// this makes sense because Range(1,10) returns a function so
// when you alert it's value, it tells you it's a function
alert(first10); // alerts - function(i) { ... }
alert(first10Odd); // alerts- function(i) { ... }
// When you execute the function in first10, it runs that function
// and the alert shows the return value from that function
// This particular function is set to return the entire array if nothing is passed
// to it
alert(first10()) ; // alerts - 1,2,3,...10
alert(first10Odd()); // alerts - 1,3,5,...19
// This particular function is set to return a specific index from the array
// if an argument is passed to it
alert(first10(0)); // alerts - 1
alert(first10Odd(9)); // alerts- 19
If you know how to use the javascript debugger, you can set a breakpoint on this line if (i === undefined) { return getAll() ;} in the inner function and you will be able to inspect all the variables that are in scope, including start, end and step from the outer function.
You may find this article useful reading as it encapsulates some of the ways that closures can be used with object declarations: http://javascript.crockford.com/private.html (not exactly what is being done here, but might help you understand them).
Welcome to javascript closures. Lets take line by line.
var first10 = Range(1,10);
var first10Odd = Range(1,20,2);
We know that Range is just a function. So, in these two lines we are just calling Range function with 2 and 3 arguments respectively.
Now, what happens when you call a function. The obvious answer is, the body of the function gets executed. What do we have in the body of the function.
if (step === undefined ) step = 1;
var arr = [], index = 0;
while(start <= end) {
arr[index] = start ;
index += 1;
start += step;
}
I hope that the above seen lines are pretty obvious and you don't have any problems with them.
var getAll = function () {
return arr;
};
What does this line do? It creates a function at run time. Why runtime? Lets see an example.
<script>
func1();
var func1 = function() {
alert("Hi");
}
</script>
<script>
func1();
function func1() {
alert("Hi");
}
</script>
If you use the first script block, it will throw error. Why? You are calling a function which hasn't been defined yet. The second case, you are defining the function during javascript parsing time itself. The type of function which was created in the first case is called anonymous function. Let us get back to getAll. Now we know that getAll is simply a variable which points to an anonymous function, lets look at what it does. It returns arr. How does it have access to arr? It is declared outside the function and so it still has access to it. Same case with
var getOne = function(n) {
return arr[n] ;
};
Now the very important part,
return function(i) {
if (i === undefined) {
return getAll();
} else {
return getOne(i);
}
};
What does it do? It returns a function. To be precise, it returns an anonymous function. Whenever Range is called, it creates a new anonymous function, which accepts one parameter and returns it. So, now what do first10 and first10Odd have? Yes. You are right, they have functions. I hope that explains
alert(first10); // alerts - function(i) { ... }
alert(first10Odd); // alerts - function(i) { ... }
Let us examine both the functions. When first10 is called with nothing, I mean, first10(), the parameter i takes the value undefined. So, we are actually making a call to the anonymous function with no parameters and it is supposed to return getAll(). If you remember, first10 was created with Range(1,10);. So, the arr will now have [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].
You might ask, when we return from the function, wont the variables declared inside the function go out of scope. The answer is Yes and No. Yes, when you simply return a value. No, when you return a function. When you return a function, the state of the variables will be maintained. This property is called closures. That is why it returns
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] for alert(first10())
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19] for alert(first10Odd())
1 for alert(first10(0))
19 for alert(first10Odd(9))
Please read more about Closure here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures