链接'绑定'并且打电话给'在JavaScript?

时间:2015-07-03 04:30:48

标签: javascript chaining

当我阅读answer时,请找var g = f.call.bind(f);。我第一眼看不到这一点。

它是否有一些直接意义,并有一些适当的使用场景?

当你在链接中使用call(or apply)bind或两者时,会发生什么?有一些法律吗?

3 个答案:

答案 0 :(得分:4)

  

var g = f.call.bind(f);。我第一眼看不到这一点。

我认为您熟悉.call().bind() Function方法?好吧,它将f.call方法绑定到函数f

请注意,f.call只是Function.prototype.call,我们在f上将其作为属性访问并不重要,因为我们不在此处调用它。

  

它有直接意义吗?

当我们查看ES6等价物时,它可能会变得更加明显:

(Function.prototype.call).bind(f) // or
(f.call).bind(f) // is basically
(...args) => f.call(...args) // or more clear
(ctx, ...args) => f.call(ctx, ...args)
  

是否有适当的使用方案?

好吧,既然你知道它做了什么,是的。它可以采用原型方法并将其转换为静态函数,该函数将实例作为第一个参数。一个例子:

function Example(n) { this.name = n; }
Example.prototype.display = function() { console.log(this.name); }

Example.display = Function.call.bind(Example.prototype.display);

var e = new Example;
e.display(); // is the same as
Example.display(e);
  

是否有任何法律可以进一步链接call / apply / bind

是:一如既往,只有链中的最后一个属性才被称为方法。在上面的示例中,f.call.bind(…)Function.prototype.call.bind(…)Function.call.apply.bind.call.bind(…)之间没有区别 - 它总是在bind上调用call

但是,通过将它们作为参数传递给对方,您可以执行some crazy things或多或少有用。

答案 1 :(得分:2)

好问题。让我们先考虑一下之前在StackOverflow上出现的一个例子:将数组中的所有字符串映射为小写。我当然可以写

strings . map(function(string) { return string.toLowerCase(); })

但这看起来有点冗长。我宁愿写

strings . map(CALL_LOWERCASE_WITH_ELT_AS_THIS)

所以我可以试试

strings . map(String.prototype.toLowerCase)

或者,使用较短的成语,有些人更喜欢

strings . map(''.toLowerCase)

因为''.toLowerCase完全等于String.prototype.toLowerCase

但当然,这不起作用,因为map将每个元素传递给指定函数作为其第一个参数,而不是this。因此,我们需要以某种方式指定一个函数,其第一个参数用于调用其他函数作为其this。当然,这正是Function.call所做的:

function.call(context)

call的第一个参数(“上下文”)在调用this时用作function

那么,问题解决了吗?我们应该只能说:

strings . map(''.toLowerCase.call)
人们已经尝试了这个,然后想知道为什么它不起作用。原因是即使我们将call toLowerCase作为回调传递给mapmap仍然不知道应该使用{调用回调{1}}的{​​1}}。我们需要明确告诉this哪个''.toLowerCase用来调用函数,在map的情况下我们可以使用它的第二个“context”参数:

this

实际上,由于map在任何函数对象上是相同的,我们可以将其简化为

strings . map(''.toLowerCase.call, ''.toLowerCase)

这很有效,可以很好地完成工作。

然而,call提供了第二个“context”参数来指定调用回调的strings . map(Function.call, ''.toLowerCase) ,这不是我们可以依赖于在所有情况下都可用的东西。我们需要一种更通用的方式来说“创建一个函数,它将map调用某个特定函数this”。

这正是Function.call的作用。它说“接受一个函数并创建另一个函数,用一个特定的this”调用它:

bind

在我们的例子中,我们要做的是“使用函数this并创建另一个函数,使用function.bind(context) Function.call来调用它。这就是

this

现在我们可以将其传递给''.toLowerCase,而不必使用第二个参数:

Function.call.bind(''.toLowerCase)

这与map完全相同,因为一般strings . map(Function.call.bind(''.toLowerCase)) 恰好等于strings . map(Function.call, ''.toLowerCase)

以下内容逐步将其分解为可读形式:

map(fn, ctxt)

如果将此构造指定为回调,例如map(fn.bind(ctxt)),则表示:

  

使用传入的第一个参数调用Function . // From the Function object call . // take the `call` method bind( // and make a new function which calls it with a 'this' of ''.toLowerCase // `toLowerCase` ) map调用call作为''.toLowerCase,根据this的定义,调用call该论点为toLowerCase

有些人喜欢通过说

来简化这一点
this

或者,使用var call = Function.call; var toLowerCase = ''.toLowerCase; strings . map(call.bind(toLowerCase)) 提供的第二个参数,只需

map

几乎可读为英文:“映射每个字符串为调用 ing toLowerCase 的结果。

另一个常见的相关用例是在promise strings . map(call, toLowerCase) 中指定回调。请考虑以下代码:

then

那很好,但有点冗长。在调用成功或失败处理程序时,promise . then(function(result) { result.frombulate(); }) 无法传入上下文以用作then。但有了上述内容,我们现在可以写:

this

promise . then(call.bind(frombulate)) 成语有其他用例,但这是最常见的用例之一:定义一个回调,其效果是调用一些函数,并将参数传递给回调{{1} }。

使用ES6胖箭头功能,当然,我可以写

call.bind

因此this提供的速记相对较少,而且很难否认胖箭版比使用promise . then(result => result.frombulate()) 更易读。

以下问题也可能有趣:Array.map and lifted functions in Javascript

答案 2 :(得分:-1)

m.call.bind(m)

可以用作以下内容的简写

function(x){return m.bind(x)()}

前者是后者的“无积分”形式, 参数是隐式的。它将与 像map()这样的列表操作,使其更短。 您可以编写以下内容:

let m   = "".toUpperCase;
let fun = m.call.bind(m);
let see = ['a','b'].map(fun);