使用javascript的.bind()方法跳过一个参数

4
在 JavaScript 中,我可以像下面这样将参数绑定到函数中:
function foo(arg1, arg2) { console.log(arguments); }
foo = foo.bind(this, 'bar');

当调用时,我们会得到以下输出...
foo('baz');
> { '0': 'bar', '1': 'baz' }

能否在 .bind() 函数中跳过参数以实现以下输出?
function foo(arg1, arg2, arg3, arg4) { console.log(arguments); }
foo = foo.bind(this, 'bar', null, 'qux');
foo('baz', 'lel');
> { '0': 'bar', '1': 'baz', '2': 'lel', '3': 'qux' }

我不这么认为...如果你不需要那个参数,为什么要传递它呢? - Arun P Johny
4个回答

5

看一下Underscore的_.partial

通过填充任意数量的参数来部分应用一个函数,而不改变其动态this值。您可以在参数列表中传递_来指定不应预先填充但应在调用时提供的参数。

在你的情况下:

function foo(arg1, arg2, arg3, arg4) { console.log(arguments); }
foo = _.partial(foo, 'bar', _, 'qux');
foo('baz', 'lel');
> { '0': 'bar', '1': 'baz', '3': 'qux', '4': 'lel'}

是的,我知道这不完全符合你想要的。你似乎想让两个参数都挤在_的位置上。除了明确指定在调用时将填充两个参数外,没有更好的方法来解决这个问题:

foo = _.partial(foo, 'bar', _, _, 'qux');

我不一定推荐您使用这个,但是至少您可以查看他们的代码并获取一些提示。
如果您希望预先确定的参数始终出现在最后,例如'qux',则需要一些额外的机制。例如,这里有一个小例程(使用ES6,但您可以进行适应),将一个函数转换为指定参数放置在参数列表末尾的函数:
function partialEnd(fn, ...predefinedArgs) {
  return function() {
    return fn.apply(this, [...arguments, ...predefinedArgs]);
  };
}

您可以像这样使用:

function foo(a, b, c) { console.log(a + b + c); }
foo = partialEnd(foo, 3);
foo(1, 2) // outputs 6

您可以结合使用 _.partial_ 占位符,以获得这样的效果:将某些参数插入到参数列表中,而其他参数始终放置在末尾。
function foo(arg1, arg2, arg3, arg4) { console.log(arguments); }
foo = _.partial(foo, 'bar', _, _);
foo = partialEnd(foo, 'lel');

foo('baz', 'lel');
> { '0': 'bar', '1': 'baz', '3': 'lel', '4': 'qux'}

2

JavaScript中不存在这样的功能,但实现一个执行相同操作的函数是相当简单的:

function curryWithNulls(fn, thisObj) {
  var curriedArgs = Array.prototype.slice.call(arguments, 2);
  var length = curriedArgs.length;

  return function() {
    var args = Array.prototype.slice.call(arguments);

    for (var i = 0; i < length || args.length; i++) {
      if (i >= length || curriedArgs[i] === null) {
        curriedArgs[i] = args.shift();
      }
    }
    return fn.apply(thisObj, curriedArgs);
  }
}

function foo(arg1, arg2, arg3, arg4) {
  console.log(arguments);
}

var curriedFoo = curryWithNulls(foo, this, 'bar', null, null, 'qux');
curriedFoo('baz', 'lel');
// => { '0': 'bar', '1': 'baz', '2': 'lel', '3': 'qux' }

这与您的示例略有不同,因为它需要为每个跳过的参数(而在您的示例中,您有一个null填充了两个参数)。这允许使用任何位置的柯里化参数进行更复杂的结构,例如:

var curriedFoo2 = curryWithNulls(foo, this, null, 'bar', null, 'qux');
curriedFoo2('baz', 'lel');
// => { '0': 'baz', '1': 'bar', '2': 'lel', '3': 'qux' }

1

不,你只是绑定了 null

函数的参数就是函数的参数;绑定一个 null 就是这样做,它不会重新定义函数,而是返回一个具有相同签名的新函数。


1
“返回一个具有相同签名的新函数” --- 实际上是一样的吗?如果绑定参数,则新函数的“arity”会减少。 - zerkms
@zerkms 是的,我也不知道该怎么表达。我的意思是,传入 null 不会改变 原始 函数的参数个数。 - Dave Newton

0

使用函数组合是可能的:

var foo = function(arg1, arg2, arg3, arg4) { console.log(arguments); }
var bar = function(arg2, arg4) { 
    return foo.bind(this, 'bar', arg2, 'qux')();
}
bar('baz', 'lel');

或者,使用现代语法:

const foo = (arg1, arg2, arg3, arg4) => console.log(arguments);
const bar = (arg2, arg4) => foo.bind(this, 'bar', arg2, 'qux')();
bar('baz', 'lel');

或者根本不绑定:

const foo = (arg1, arg2, arg3, arg4) => console.log(arguments);
const bar = (arg2, arg4) => foo(this, 'bar', arg2, 'qux', arg4);
bar('baz', 'lel');

注意调用绑定的函数(注意在bind后面有这些括号());


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接