使用Apply或Call创建一个无点功能?

时间:2018-12-14 02:37:20

标签: javascript functional-programming apply method-call pointfree

比方说,我想创建一个修剪其输入的函数,我可以做到的一种方法就是简单地

x => x.trim()

另一种方法是

x => String.prototype.trim.call(x)

具有的优势在于,如果x.trim()定义了替代,我仍然可以从原型中获取实现。通过扩展,如果我想在.map()中使用相同的功能,则可以两者之一

[" foo", "bar "].map(x => x.trim())
[" foo", "bar "].map(x => String.prototype.trim.call(x));

我想做一个pointfree function。我不明白的是为什么不能使用由.call

创建的未调用函数
[" foo", "bar "].map(String.prototype.trim.call);

我还尝试了.apply,因为没有参数实际上是同一回事。

同样,在地图之外,您也不能使用函数.call函数

> fn = String.prototype.trim.call
[Function: call]
> fn('asdf')
TypeError: fn is not a function

我的问题是

  1. 在上面,String.prototype.trim.call返回的函数到底是做什么的?那是什么功能?
  2. 为什么我尝试使用.call无效?
  3. 反正有.bind.apply.call这样做吗?

2 个答案:

答案 0 :(得分:1)

有趣的问题!归结为Array.prototype.map的签名:

var new_array = arr.map(function callback(currentValue[, index[, array]]) {
    // Return element for new_array
}[, thisArg])

了解您注意到的行为的关键是可选的thisArg-这是将提供给回调的上下文

此外,from the spec

  

如果提供thisArg参数来映射,它将用作回调的this值。否则,未定义的值将用作此值。

因此,这意味着undefined将用作回调的上下文,在本例中为String.prototype.trim.call

在这里变得有趣起来……Function.prototype.callString.prototype.trim.call继承了)的正常上下文是它调用的函数,即本例中的String.prototype.trimFunction.prototype.call的第一个参数提供了将要调用的函数的上下文。

<< Array >>.map(String.prototype.trim.call)的情况下,提供给String.prototype.trim.call的上下文为undefined,这意味着我们最终尝试使用来自undefined的元素的上下文来调用String.prototype.trim数组。全清?肯定有点思想上的转变。

我们可以通过在thisArg中将<< Array >>.map(callback, thisArg)作为Function.call并将console.log([" foo", "bar "].map(Function.call, String.prototype.trim));用作回调来利用这种行为来达到我们想要的效果:

String.prototype.trim

另一种思考方式是Function.call为{{1}}提供上下文以生成绑定函数,然后数组的每个元素为绑定函数提供上下文。

答案 1 :(得分:1)

  

我不明白的是为什么不能使用由.call创建的未调用函数

[" foo", "bar "].map(String.prototype.trim.call);

这里的问题是所有函数都从call继承相同的Function.prototype方法;所以以上等同于

[" foo", "bar "].map(Function.prototype.call);

要使代码正常工作,call需要“记住”您是从String.prototype.trim而不是其他函数获得的;但这根本不是方法调用在JavaScript中的工作方式。在像foo.bar()这样的方法调用表达式中,foo不仅是其bar属性被作为函数调用的对象,它还隐式地作为{{1} } 该功能。对于thisString.prototype.trim.call(x)知道调用call的唯一原因是您使用的是方法调用语法,因此可以从String.prototype.trim中获取它。 / p>


  
      
  1. 在上面,this返回的函数到底是做什么的?那是什么功能?
  2.   

这是一个方法,它带有一个对象和零个或多个参数,并且在对一个函数进行调用时,将对该函数作为对该对象的方法进行调用,并传递这些参数。

  
      
  1. 为什么我尝试使用String.prototype.trim.call无效?
  2.   

因为它尝试将.call作为自由函数而不是方法来调用;因此call不会收到call自变量告诉它要调用什么函数,因此它无法完成其工作。 (它很可能会收到“默认对象”,例如this作为其window参数;但是我不确定某些细微之处。您可以在其中尝试this您的测试平台,看看它能为您的环境带来什么。)

  
      
  1. 反正有[" foo", "bar "].map(function () { return this; }).bind.apply这样做吗?
  2.   

是;你可以这样写:

.call

其中[" foo", "bar "].map(Function.prototype.call.bind(String.prototype.trim)) 是一个函数,该函数在被调用时会在Function.prototype.call.bind(String.prototype.trim)上调用call。 (换句话说,String.prototype.trim处理“记住” bind是要作为String.prototype.trim传递的对象。)

也就是说,我真的认为您的原始版本,

this

非常优越。如果某人重写了[" foo", "bar "].map(x => x.trim()) ,您应该相信它是有充分理由的,您确实应该调用该重写,而不是强制使用继承的替代。