A famous trick question, some of you may have seen:

['2'.'3'.'4'].map(parseInt);
Copy the code

Say the result of executing the code above.

If your brain doesn’t say [2, 3, 4], you’re definitely wrong. In fact, the actual result is [2, NaN, NaN]. Why is that? This is because the map operator takes two parameters. The first parameter is the element of the array to be iterated over, and the second parameter is the index of that element. So [‘ 2 ‘, ‘3’, ‘4’). The map (parseInt) effectively performed [parseInt (‘ 2 ‘, 0), parseInt (‘ 3 ‘, 1), parseInt (‘ 4 ‘, 2)]. The result is [2, NaN, NaN].

We are not here today to talk about why parseInt(‘2’, 0) is 2 and parseInt(‘3’, 1) is NaN, but we should expect parseInt(‘2’, 10) and parseInt(‘3’, 10), Convert the strings ‘2’ and ‘3’ to a decimal number.

So, the correct way to write it is:

['2'.'3'.'4'].map(num= > parseInt(num, 10));
Copy the code

The above notation is simple for this problem and has little to do with functional programming. However, if the problem is thought of generically in terms of process abstraction, it looks like this:

['2'.'3'.'4'].map(parseInt.bindRight(null.10));
Copy the code

BindRight is the opposite of bind. BindRight is equivalent to bind from right to left:

function add(x, y, z){
    return 100*x + 10 * y + z;
}

let add1 = add.bind(null.1.2);
let add2 = add.bindRight(null.1.2);

add1(3); / / 123
add2(3); / / 321
Copy the code

To implement bindRight, consider various scenarios that are slightly more complicated, but not too cumbersome:

Function.prototype.bindRight = function(thisObj, ... values){
  let fn = this, len = fn.length - values.length;
  return function(. args){
    let rest = [], rargs = values.reverse();

    if(len > 0){
      rest = args.slice(0, len);
    }

    returnfn.apply(thisObj, rest.concat(rargs)); }}Copy the code

This implements the bindRight we need, and the complete result is as follows:

Function.prototype.bindRight = function(thisObj, ... values){
  let fn = this, len = fn.length - values.length;
  return function(. args){
    let rest = [], rargs = values.reverse();
    
    if(len > 0){
      rest = args.slice(0, len);
    }

    returnfn.apply(thisObj, rest.concat(rargs)); }}console.log(["2"."3"."4"].map(parseInt));

console.log(["2"."3"."4"].map(parseInt.bindRight(null.10)));

function add(x, y, z){
    return 100*x + 10 * y + z;
}

let add1 = add.bind(null.1.2);
let add2 = add.bindRight(null.1.2);

console.log(add1(3)); / / 123
console.log(add2(3)); / / 321

Copy the code

The bindRight code is not complicated. If bindRight has more arguments than the function parameters, it simply passes the parameter order reverse to the original function, otherwise it completes the parameters before the function.

In addition to implementing bindRight this way, there is a more basic way to manipulate combinations of higher-order functions:

Function.prototype.reverseArgs = function(){
  let fn = this;
  return function(. args){
    return fn.apply(this, args.reverse()); }}Function.prototype.fixArgsLength = function(len){
  let fn = this;
  return function(. args){
    args.length = len || fn.length;
    return fn.apply(this, args); }}Function.prototype.bindRight = function(thisObj, ... values){
  return this.reverseArgs().bind(thisObj, ... values).reverseArgs().fixArgsLength(1);
}
Copy the code

In the above code we combine bindRight using reverseArgs with fixArgsLength and bind. ReverseArgs is a high-order function that reverse-orders its arguments. FixArgsLength is a high-order function that fixes the number of arguments in a function. As you can see, bindRight is a reverseArgs and then bind, Finally, fixArgsLength (think about why fixArgsLength is needed). That will do.

However, you can also use fixArgsLength directly for the above problem

["2"."3"."4"].map(parseInt.fixArgsLength(1)); / / [2, 3, 4]
Copy the code

Finally, the complete code:

Function.prototype.reverseArgs = function(){
  let fn = this;
  return function(. args){
    return fn.apply(this, args.reverse()); }}Function.prototype.fixArgsLength = function(len){
  let fn = this;
  return function(. args){
    args.length = len || fn.length;
    return fn.apply(this, args); }}Function.prototype.bindRight = function(thisObj, ... values){
  return this.reverseArgs().bind(thisObj, ... values).reverseArgs().fixArgsLength(1);
}

var a = parseInt.bind(null.10);


console.log(["2"."3"."4"].map(parseInt));
console.log(["2"."3"."4"].map(parseInt.bindRight(null.10)));
console.log(["2"."3"."4"].map(parseInt.fixArgsLength(1)));

function add(x, y, z){
    return 100*x + 10 * y + z;
}

let add1 = add.bind(null.1.2);
let add2 = add.bindRight(null.1.2);

console.log(add1(3)); / / 123
console.log(add2(3)); / / 321

Copy the code

If you have any questions, welcome to discuss.