本文需要读者对JavaScript有较深的理解,尤其是要充分理解函数的 this 和函数式编程中涉及的部分概念。文章翻译比较累人,暂分为2部分,本文是其一。
我们已经知道,ECMA-262-5 对 Function.prototype 的 bind 方法进行了标准化。这个方法的当前版本的源码来自 “Prototype.js” 库,尽管标准化后的版本有一些不同。该方法为大众所知,并且在ES3中得到了成功的应用,所以本笔记的主要目的是展示ES5实现的技术细节和差异(它们可能会造成困惑)。
Purposes 用途
当前的 Function.prototype.bind 实现有两个用途,一是 静态绑定 this 的值,二是函数偏应用(partial application of a function)。让我们考虑一下。
Bound this value 绑定 this 的值
bind 方法的主要用途是静态地绑定 this 的值,以便后续调用函数时其 this 指向是固定的。正如我们在《ECMA-262-3 in detail. Chapter 3. This》 所介绍的那样。函数在每次调用时其 this 都是可变的。因此,bind 的主要目的是修复这个“问题”。例如,当我们将对象的方法添加为某个DOM元素的事件处理器时。使用绑定函数(bound function),在事件处理中我们可以始终得到正确的 this 值。
var widget = {state: {...},onClick: function onWidgetClick(event) {if (this.state.active) {...}}};document.getElementById("widget").onclick = widget.onClick.bind(widget);
我在上面的示例中使用了添加click事件简单方式——通过 onclick 方法,但在实践中,你可以使用 addEventListener 或 attachEvent 以注册多个监听器。但是,该示例的目的是展示如何预设定 this 的值并将其绑定到 widget 对象,如此,this.state 属性就能正常访问了。
Partial application 偏应用(部分应用)
当前 “bind” 实现的另一个用途是 curring(柯里化,或更接近数学用语——函数的偏应用)。它是一种将一个接收多个参数的函数转换为一个函数链的技术,链中每个函数只接收一个参数,在全部调用结束后,产生和之前的函数相同的结果。这意味着我们可以基于其他函数生成新的函数,并且可以预定义新函数的某些(或所有)参数。将新函数与剩余的参数(最后一部分参数)应用到一起就构成了函数的部分应用(偏应用)。
function foo(x, y) {// partialif (typeof y == "undefined") {return function partialFoo(y) {// completereturn x + y;};}// completereturn x + y;}foo(10, 20); // 30foo(10)(20); // 30var partialFoo = foo(10); // functionpartialFoo(20); // 30
偏应用的实际理念可能是,一些经常被调用的函数,传给它们的部分参数总是一样的。在这种情况下,可以方便地封装这些参数,生成新的偏函数(partial function)。另一个很好的实际例子是,在绑定事件监听器的同时,也绑定一些数据,这些数据将在监听器被激活时用到。event 对象本身就可以作为这种绑定数据的一个最简单的例子。理论上,偏应用与一些数学定理有关,也与函数只有一个参数的 lambda calculus 有关。
因此,实际上,使用 “bind” 方法,我们可以生成偏函数:
function foo(x, y) {return x + y;}var partialFoo = foo.bind(null, 10);partialFoo(20) // 30
在这个例子中,静态绑定 this 的值对我们来说不是必需的(我们甚至没有在函数中使用this 关键字),但是 curring 是必需的。当然,我们也可以将 bind 方法的这两个用途结合起来。
不要走开,待续。。
文章译自 Dmitry Soshnikov 所写的 《Note 1. ECMAScript. Bound functions.》,点击 阅读原文 可查看。




