There is a curry function from https://www.30secondsofcode.org/js/s/curry.
const curry = (fn, arity = fn.length, ...args) => {
if (args.length >= arity) {
return fn(...args)
} else {
return curry.bind(null, fn, arity, ...args) // line(*)
}
}
console.log(curry(Math.pow)(2)(10)) // 1024
console.log(curry(Math.min, 3)(10)(50)(2)) // 2
Why using bind is necessary in line(*)? Can it be replaced with
return curry(fn, arity, ...args) // line(**)
?
There are only two reasons to ever use Function#bind:
When you want to bind the function to a particular context object. Practically speaking, when you want to make sure ahead of time that the this keyword inside the function will refer to a particular, known object.
When you want to pre-define some arguments, a.k.a. "partial function application".
The second case lends itself perfectly to what function currying is all about - making an N-ary function flexibly callable like:
fn(arg1, arg2, ..., argN), or
fn(arg1, arg2, ...)(argN), or
fn(arg1, arg2)(..., argN), or
fn(arg1)(arg2)(...)(argN).
The important thing to notice here is that we need multiple separate functions for all cases but the first. Let's say you have a worker function that takes 3 arguments. You can...
...pass enough arguments for the worker function, i.e. 3 or more. Then curry() calls the worker function with those 3 arguments and returns the result.
This makes fn(arg1, arg2, arg3) possible.
...pass too few arguments for the worker function. Then curry() does not call the worker, but must return a new function which takes the remaining number of arguments.
This makes all of fn(arg1)(arg2, arg3) and fn(arg1, arg2)(arg3) and fn(arg1)(arg2)(arg3) possible.
Function#bind covers the second case: It creates a new wrapper function for the worker and pre-fills some of the worker's argument slots with the given values. The context object is irrelevant for that intention, so using null here is fine.
const curry = (fn, arity = fn.length, ...args) =>
// enough arguments ? call : remember arguments so far & defer
args.length >= arity ? fn(...args) : curry.bind(null, fn, arity, ...args);
So to answer the question: No, you can't use return curry(fn, arity, ...args) because this does not do the most important thing, which is to create a new function.
Example: Let's say we have a worker function that searches a string and returns the number of hits.
const search = (str, substr) => {
var hits = 0, pos = 0;
while (true) {
pos = str.indexOf(substr, pos) + 1;
if (pos) hits++; else return hits;
}
}
Now we could create a curried version that remembers the target string for us and we only need to switch the last argument:
const flexibleSearch = curry(search);
const reusableSearch = flexibleSearch("... a ... b ... c ... a ... b ... a");
reusableSearch("a") // -> 3
reusableSearch("b") // -> 2
reusableSearch("c") // -> 1
reusableSearch("d") // -> 0
#Tomalak is correct
Lets say you have a function that takes 100 parameters fn(1,2,3,...100) {}.
fn.bind(null, 99, 100) creates a new function with preset leading argument. In our example will use the default values for parameters 1,2,...97,98 and expect two parameters as input for the new function that will be used as parameter 99, and 100.
In this case, we are currying a function to accept partial arguments.
You can go through these to get a deeper understanding
Wiki for currying and
MDN docs for binding partial functions
Related
I am Korean, so I hope you could understand it with my awkward English skills
I am studying arrow function expressions
and here is my question with source code
var arguments = [1, 2, 3];
var arr = () => arguments[0];
console.log(
arr()
)
function foo(n){
var f = () => arguments[0] + n
console.log(arguments[0]) //5
console.log("----arguments[0]")
return f();
}
console.log(
foo(5)
)
console.log("---------------------")
function fooo(n){
var f = (...arguments) => arguments[0] + n
console.log(...arguments) //5
console.log("----...arguments")
return f(2);
}
console.log(
fooo(5)
)
I don't get why the second function's console.log = 10 and third function's = 7
can anyone explain to me the order code process and why that output is?
thank you.
In JS, every conventional function has a built-in object called arguments. However, Arrow functions do not have this built-in object. So, if referred to arguments from within an Arrow function, the reference automatically goes to any external variable declared by that name.
The result you see is due to this effect. In regular function calls. your reference to the arguments global variable actually refers to their in-built arguments object.
The following code demonstrates this effect.
let arguments = 'this is a string';
function argumentsTest() {
console.log(arguments);
}
let argumentsArrowTest = () => {
console.log(arguments);
}
argumentsTest(10); //{0: 10}
argumentsArrowTest(10); // this is a string
In an arrow function, arguments, like this, will refer to either
an outer identifier named arguments (though it's very unusual to call a variable arguments due to name collision), or
the arguments provided to a full-fledged function
whichever is closer, lexically.
In foo,
var f = () => arguments[0] + n
is an arrow function, so arguments refers to an outer binding. The outer environment is
function foo(n){
var f = () => arguments[0] + n
so arguments refers to the arguments provided to foo. Here, it's similar to doing
function foo(n){
const theArguments = [n];
var f = () => theArguments[0] + n
And since the argument passed to foo is 5, that plus n (the same argument) is 10.
In the third function, the same logic applies. Inside an arrow function, arguments refers to the closest identifier named arguments, or the closest function. Here, it's the parameters:
var f = (...arguments) => arguments[0] + n
Since f is called with a single argument, this simplifies to
var f = (arg) => arg + n
That argument is 2, and the n is what's passed to fooo, which is 5. Add them together, you get 7.
Can I call a function with array of arguments in a convenient way in JavaScript?
Example:
var fn = function() {
console.log(arguments);
}
var args = [1,2,3];
fn(args);
I need arguments to be [1,2,3], just like my array.
Since the introduction of ES6, you can sue the spread syntax in the function call:
const args = [1,2,3];
fn(...args);
function fn() {
console.log(arguments);
}
Before ES6, you needed to use apply.
var args = [1,2,3];
fn.apply(null, args);
function fn() {
console.log(arguments);
}
Both will produce the equivalent function call:
fn(1,2,3);
Notice that I used null as the first argument of the apply example, which will set the this keyword to the global object (window) inside fn or undefined under strict mode.
Also, you should know that the arguments object is not an array, it's an array-like object, that contains numeric indexes corresponding to the arguments that were used to call your function, a length property that gives you the number of arguments used.
In ES6, if you want to access a variable number of arguments as an array, you can also use the rest syntax in the function parameter list:
function fn(...args) {
args.forEach(arg => console.log(arg))
}
fn(1,2,3)
Before ES6, if you wanted to make an array from your arguments object, you commonly used the Array.prototype.slice method.
function fn() {
var args = Array.prototype.slice.call(arguments);
console.log(args);
}
fn(1,2,3);
Edit: In response to your comment, yes, you could use the shift method and set its returned value as the context (the this keyword) on your function:
fn.apply(args.shift(), args);
But remember that shift will remove the first element from the original array, and your function will be called without that first argument.
If you still need to call your function with all your other arguments, you can:
fn.apply(args[0], args);
And if you don't want to change the context, you could extract the first argument inside your function:
function fn(firstArg, ...args) {
console.log(args, firstArg);
}
fn(1, 2, 3, 4)
In ES5, that would be a little more verbose.
function fn() {
var args = Array.prototype.slice.call(arguments),
firstArg = args.shift();
console.log(args, firstArg);
}
fn(1, 2, 3, 4);
In ECMAScript 6, you can use spread syntax (...) for that purpose. It's way simpler and easier to understand than Function.prototype.apply().
Code example:
const fn = function() {
console.log(arguments);
}
const args = [1,2,3];
fn(...args);
So I get that an array of [200,599] is returned from the promise and the callback function inside spread is being passed into Function.apply.bind, but now I'm lost. How is the array of [200,599] split into x and y? How exactly does the apply.bind work?
function getY(x) {
return new Promise( function(resolve,reject){
setTimeout( function(){
resolve( (3 * x) - 1 );
}, 100 );
} );
}
function foo(bar,baz) {
var x = bar * baz;
// return both promises
return [
Promise.resolve( x ),
getY( x )
];
}
function spread(fn) {
return Function.apply.bind( fn, null );
}
Promise.all(
foo( 10, 20 )
)
.then(
spread( function(x,y){
console.log( x, y ); // 200 599
} )
)
.apply() is a method on function objects. Like so:
console.log(Math.max.apply(null, [1, 2, 3])); // 3
.apply() accepts two arguments, the context (what would become this inside of the target function) and an iterable of arguments (usually an array, but the arguments array like also works).
.bind() is a method on function objects. Like so:
const x = {
foo: function() {
console.log(this.x);
},
x: 42
}
var myFoo = x.foo.bind({x: 5});
x.foo(); // 42
myFoo(); // 5
.bind() takes a context (what would become this), and optionally, additional arguments, and returns a new function, with the context bound, and the additional arguments locked
Since .apply() is a function in on itself, it can be bound with .bind(), like so:
Function.prototype.apply.bind(fn, null);
Meaning that the this of .apply() would be fn and the first argument to .apply() would be null. Meaning that it would look like this:
fn.apply(null, args)
Which would spread the parameters from an array.
Spread takes a function and binds the apply method to, partially applying the null argument. So in short,
spread(fn)
is transformed to
args => fn.apply(null, args)
which is the same as using the ES6 spread syntax
args => fn(...args)
where the function got its name from.
If you want the long answer, remember what bind does:
method.bind(context, ...args1)
returns a function that works like
(...args2) => method.call(context, ...args1, ...args2)
In our case, method is apply, the context is fn and the first arguments are null, so the call
Function.apply.bind( fn, null )
will create a function that works like
(...args2) => (Function.apply).call(fn, null, ...args2)
which is equivalent to the fn.apply(…) call above, given that apply is the method inherited from Function.prototype in both accesses.
The spread function is just a utility function to convert an array, into parameters passed to a function. The apply is doing the converting, and the bind is binding it to the calling function so that the "this" context is connected to same function.
To see how spread is working in a simpler form ->
spread(function (x,y){console.log(x,y);})([1,2])
You will get the answer, 1 2, as 1 is passed to x, and 2 is passed to y.
So in your example your promise.all is returning an array of resolved promises.
These are then getting mapped to parameters to your function(x,y).
The reason it works is the "destructuring" nature of apply (if given an array of values, they would be provided spreaded to the function you use apply on).
Now back to your code when calling bind on apply, the value returned is a function which returns the same function provided to bind, the only thing different is when executed it would be called using apply (with an array as thisArg in your case), but it isn't going to be executed until you call it.
In your case when the promise has resolved, the function provided tothen woule be executed with an array of arguments provided by Promise resolution.
function spread(fn){
let boundedFn = fn.bind(fn)
return function(arg){
return boundedFn.apply(null,arg)
}
}
spread((x, y, c) => console.log(x, y, c))([1,2,3])
// or
Promise.resolve([6, 5]).then(spread((a, b) => console.log(a, b)))
The reason bind is provided (in your code) with null as second param is to prevent the array provided by the caller from being given to apply as its first param, which reserved for this.
Everything started with this Question
Then an answer from #MinusFour
var slice = Function.call.bind(Array.prototype.slice);
I wanted to understand, whats happening under the hood,
my curiosity hence this Question.
what to achieve ? understanding of "Function.call.bind".
Step-by-step approach for the same
Started with MDN
NOTE : I am using NodeJS here
1)
var adder = new Function('a', 'b', 'return a + b');
console.log(adder(2, 6));
**OUTPUT **
8
This is expected, Nothing Fancy
2)
This is our end goal , calling function myFunc from the bounded
function (Function.call.bind(myFunc))
function myFunc(a, b) {
console.log(arguments.length, a, b, a + b);
}
3)
var adder = Function(myFunc);
console.log(adder.toString())
OUTPUT
function anonymous() { function myFunc(a, b) { console.log(a + b); } }
Expected! above code does nothing, because i am calling 'anonymous' ,
and it does nothing.
4)
var adder = Function.call(myFunc);
console.log(adder.toString())
OUTPUT
function anonymous() {
}
Expected!. '.call' calls 'Function', with 'this' set to 'myFunc' and with out any param or function body. so an empty anonymous function is the output. Now, I can do "var adder = Function.call(myFunc,myFunc);" to create the same function from step-3
So far so good
5)
var adder = Function.call.bind(myFunc);
console.log(adder.toString())
adder(2,6);
OUTPUT
function () { [native code] }
1 6 undefined NaN
Here first param is not passed to the 'myFunc' function.
this is taken as 'this' for function 'adder' (the bounded Function.call) ?
Now I understand(or did I misunderstood?) until now, but then
How does below code works ?
var slice = Function.call.bind(Array.prototype.slice);
function fn(){
var arr = slice(arguments);
}
in my case first param to adder is discarded(or Function.call consider it as 'this' for it), same should happen with slice above right ?
Anyway, i wanted to document it for a reference
I'm afraid you've gone off in slightly the wrong direction. This line:
var slice = Function.call.bind(Array.prototype.slice);
never calls Function and never arranges for it to be called later. The only thing Function is being used for there is its call property. Function could have been Object or Date or RegExp or any other function, or could have been Function.prototype; doesn't matter. Function.prototype would have been more direct and possibly less confusing.
This is a bit tricky to explain because it involves two layers of dealing with this, where this is different things at different times:
The call function calls functions with a specific this value you give it as its first argument, passing along any other arguments you give it. For example:
function foo(arg) {
console.log("this.name = " + this.name + ", arg = " + arg);
}
var obj = {name: "bar"};
foo.call(obj, "glarb"); // "this.name = bar, arg = glarb"
There, because we called call on foo, call called foo with this set to obj and passing along the "glarb" argment.
call knows what function it should call based on what this is during the call call. foo.call sets this during call to foo. That can be confusing, so let's diagram it:
foo.call(obj, "glarb") calls call:
call sees this = foo and the arguments obj and "glarb"
call calls this (which is foo):
foo sees this = obj and the single argument "glarb"
With regard to slice, you normally see call used with it used to create an array from something array-like that isn't really an array:
var divArray = Array.prototype.slice.call(document.querySelectorAll("div"));
or
var divArray = [].slice.call(document.querySelectorAll("div"));
There, we call call with this set to Array.prototype.slice (or [].slice, which is the same function) and passing in the collection returned by querySelectorAll as the first argument. call calls the function it sees as this, using its first argument as this for that call, and passing along any others.
So that's the first layer of this stuff.
bind is another function that functions have, and it's similar to call but different: Where call calls the target function with a given this and arguments, bind creates and returns a new function that will do that if you call it. Going back to our foo example:
function foo(arg) {
console.log("this.name = " + this.name + ", arg = " + arg);
}
var obj = {name: "bar"};
var fooWithObjAndGlarb = foo.bind(obj, "glarb");
fooWithObjAndGlarb(); // "this.name = bar, arg = glarb"
This is called binding things (obj and the "glarb" argument) to foo.
Unlike call, since bind creates a new function, we can add arguments later:
function foo(arg) {
console.log("this.name = " + this.name + ", arg = " + arg);
}
var obj = {name: "bar"};
var fooWithObj = foo.bind(obj);
fooWithObj("glarb"); // "this.name = bar, arg = glarb"
Okay, now we have all our working pieces. So what's happening in your code? Let's break it into parts:
// Get a reference to the `call` function from the `call` property
// on `Function`. The reason `Function` has a `call` property is that
// `Function` is, itself, a function, which means its prototype is
// `Function.prototype`, which has `call` on it.
var call = Function.call;
// Get a reference to the `slice` function from `Array.prototype`'s `slice` property:
var rawSlice = Array.prototype.slice;
// Create a *bound* copy of `call` that, when called, will call
// `call` with `this` set to `rawSlice`
var callBoundToSlice = call.bind(rawSlice);
(callBoundToSlice is just called slice in your question, but I'm using callBoundToSlice to avoid confusion.) Binding rawSlice to call was the first layer of this handling, determining what call will see as this. Calling callBoundToSlice will call call with this set to rawSlice. Then call will call the function it sees as this (rawSlice), using its first argument as the value for this during the call (the second layer of this handling) and passing on any further arguments.
So our forEach with a collection from querySelectorAll can now look like this:
callBoundToSlice(document.querySelectorAll("div")).forEach(function(div) {
// Each div here
});
That passes the collecton returned by querySelectorAll into callBoundToSlice, which calls call with this as rawSlice, which calls Array.prototype.slice with this set to the collection. Array.prototype.slice uses this to copy the array.
All of that said, using slice to turn array-like objects into true arrays is a bit out of date. ES2015 introduces the Array.from method, which can be shimmed/polyfilled on JavaScript engines that don't have it yet:
var divArray = Array.from(document.querySelectorAll("div"));
Reading about functional programming - got to currying, example has a simple currying function. I understand everything except the last else block.
var curry = function (fn, fnLength) {
fnLength = fnLength || fn.length;
return function () {
var suppliedArgs = Array.prototype.slice.call(arguments);
if (suppliedArgs.length >= fn.length) {
return fn.apply(this, suppliedArgs);
} else if (!suppliedArgs.length) {
return fn;
} else {
return curry(fn.bind.apply(fn, [this].concat(suppliedArgs)), fnLength - suppliedArgs.length);
}
};
};
If the supplied args are >=, call the function with the supplied arguments.
Else if suppliedArgs.length is falsy, return the original function without doing anything.
Else ???
I think recursively call the function?
I don't understand what .bind.apply accomplishes.
Is [this] just in an array because suppliedArgs.push wouldn't return the array?
Start by looking at how you call Function#bind():
fun.bind(thisArg[, arg1[, arg2[, ...]]])
Then consider how you use Function#apply():
fun.apply(thisArg, [argsArray])
So given for bind() we need to call it on a function, and give it multiple parameters (not an array), and all we have is an array of arguments (suppliedArgs in the code), then how can we do that? Well, the main way you can call a function that takes multiple arguments instead of a single argument that is an array is to use .apply() on the function. So then we have fn.bind.apply(...something...).
The first parameter to .apply() is the this value - which needs to be the function to be bound in the case of .bind() (see below for an explanation of why). Hence fn.bind.apply(fn, ...).
Then, the second parameter to .apply() is an array of all the arguments to the function you are invoking, which in the case of .bind() is thisArg[, arg1[, arg2[, ...]]]. Hence we need a single array, with the first value being the value for this within the function, followed by the other arguments. Which is what [this].concat(suppliedArgs) produces.
So the whole fn.apply.bind(fn, [this].concat(suppliedArgs)) thing produces a correctly bound function that will have the supplied arguments to the current function "prefilled", with the correct this context. This function that is produced is then passed as the fn parameter in a recursive call to curry(), which in turn will produce another function in the same way as the top level call will.
The overall effect is that whenever you call a function created by curry(), if you don't pass the expected number of parameters, you will get a new function which takes the remaining number of parameters, or you will evaluate the original function with the entire list of parameters passed in correctly.
e.g.
function addAllNums(a, b, c, d, e) {
return a + b + c + d + e;
}
var curriedAddAll = curry(addAllNums, 5);
var f1 = curriedAddAll(1); // produces a function expecting 4 arguments
var f2 = f1(2, 3); // f2 is a function that expects 2 arguments
var f3 = f2(4); // f3 is a function that expects 1 argument
var f4 = f3(5); // f4 doesn't expect any arguments
var ans = f4(); // ans = 1 + 2 + 3 + 4 + 5 = 15.
// OR var ans = f3(5); => same result
Why the different thisArg values?
Probably the most confusing thing about this line of code is the two different values for thisArg in .bind() and .apply().
For .apply(), the thisArg is what you want the value of this to be inside the function you are calling .apply() on. e.g. myFunction.apply(myObj, ['param1', 'param2']) is equivalent to myObj.myFunction('param1', 'param2').
In this particular case, .bind() is executed on the fn function, so we want fn to be the this value for .bind(), so it knows what function it is creating a bound version of.
For .bind(), the thisArg is what the value of this will be inside the bound function that is returned.
In our case, we want to return a bound function that has the same this value as we currently have. In other words, we want to maintain the this value correctly within the new function, so it doesn't get lost as you create new functions which happens when you call a curried function with less arguments than it expects.
If we did not maintain the this value correctly, the following example wouldn't log the correct value of this. But by maintaining it, the correct value will be output.
var myObj = {
a: 1,
b: curry(function (a, b, c, d) {
console.log('this = ', this);
return a + b + c + d;
})
};
var c = myObj.b(1,1,1); // c is a function expecting 1 argument
c(1); // returns 4, and correctly logs "this = Object {a: 1, b: function}"
// if "this" wasn't maintained, it would log the value of "this" as
// the global window object.
The last else block is the main and most important part of the curry function, as it is the actual line that carries the logic for currying.
return curry(fn.bind.apply(fn, [this].concat(suppliedArgs)), fnLength - suppliedArgs.length);
This is what returns the new function that needs n-1 arguments from your previous function. Why? It's a combination of multiple things:
fn.bind.apply simply calls a function in the context of the function itself, while supplying the needed args (suppliedArgs). Note how the next parameter to curry is fnLength - suppliedArgs.length, which reduces the arguments needed to what was passed.
Let's explain it with the help of ES6. Things are going to become more obvious.
// Imagine we have the following code written in ES5
function fn(a, b, c) {
console.log(a, b, c);
}
var arr = [1, 2, 3];
var funcWithBoundArguments = fn.bind.apply(fn, [null].concat(arr));
Let's convert ES5 to ES6 code
// ES6
function fn(a, b, c) { console.log(a, b, c) }
let arr = [1,2,3];
let funcWithBoundArguments = fn.bind(null, ...arr)
You see? When you bind a function we have to explicitly enumerate all the arguments like:
fn.bind(null, 1, 2, 3)
But how could we bind the content of an array if we don't know its content in advance?
Right, we have to use .bind.apply() where:
the 1st argument of apply is the function (fn) we bind
the 2nd argument is an array which gets the context (as the first item of array) that we bind our function to and the rest of the items of the array are the arguments (which number is variable) we bind to our function (fn).