上面代码中,函数其实是add函数的一个特殊版本,通过将一个参数绑定为7,就可以从add得到add7

    1. // bind 方法
    2. const add7 = add.bind(null, 7);
    3. // 箭头函数
    4. const add7 = x => add(x, 7);

    上面两种写法都有些冗余。其中,bind方法的局限更加明显,它必须提供this,并且只能从前到后一个个绑定参数,无法只绑定非头部的参数。

    现在有一个,使得绑定参数并返回一个新函数更加容易。这叫做函数的部分执行(partial application)。

    1. const add = (x, y) => x + y;
    2. const addOne = add(1, ?);
    3. const maxGreaterThanZero = Math.max(0, ...);

    根据新提案,?是单个参数的占位符,是多个参数的占位符。以下的形式都属于函数的部分执行。

    1. // 等同于
    2. const g = (x, ...y) => f(x, 1, ...y);

    函数的部分执行,也可以用于对象的方法。

    1. let obj = {
    2. f(x, y) { return x + y; },
    3. };
    4. const g = obj.f(?, 3);
    5. g(1) // 4

    注意点

    函数的部分执行有一些特别注意的地方。

    (1)函数的部分执行是基于原函数的。如果原函数发生变化,部分执行生成的新函数也会立即反映这种变化。

    上面代码中,定义了函数的部分执行以后,更换原函数会立即影响到新函数。

    1. let a = 3;
    2. const f = (x, y) => x + y;
    3. g(1); // 4
    4. // 改变 a 的值
    5. a = 10;
    6. g(1); // 11

    上面代码中,预先提供的参数是变量a,那么每次调用函数g的时候,才会对a进行求值。

    (3)如果新函数的参数多于占位符的数量,那么多余的参数将被忽略。

    1. const f = (x, ...y) => [x, ...y];
    2. const g = f(?, 1);
    3. g(2, 3, 4); // [2, 1]

    上面代码中,函数g只有一个占位符,也就意味着它只能接受一个参数,多余的参数都会被忽略。

    写成下面这样,多余的参数就没有问题。

    1. const f = (...x) => x;
    2. const g = f(..., 9, ...);
    3. g(1, 2, 3); // [1, 2, 3, 9, 1, 2, 3]

    上面代码中,定义了两个...占位符,真正执行的时候,它们的值是一样的。