当我阅读answer时,请找var g = f.call.bind(f);
。我第一眼看不到这一点。
它是否有一些直接意义,并有一些适当的使用场景?
当你在链接中使用call(or apply)
或bind
或两者时,会发生什么?有一些法律吗?
答案 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
。
答案 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
作为回调传递给map
,map
仍然不知道应该使用{调用回调{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);