函数式JavaScript(3):.apply()、.call() 和arguments对象

416 查看

我们正在寻求调校JavaScript的方式,使得我们可以做些真正的函数式编程。为了做到这一点,详细理解函数调用和函数原型是非常有必要的。

这是一个(待定)关于使用JavaScript进行函数式编程系列的第三篇文章。如果你是刚刚加入的,你可以跳回去看看之前的文章。

函数原型

现在,不管你是已经读了还是忽略掉上面的链接所对应的文章,我们准备继续前进!
如果我们点开了我们喜欢的浏览器+JavaScript控制台,让我们看一下Function.prototype对象的属性:

这里的输出依赖于你使用的浏览器和JavaScript版本。(我用的是Chrome 33)
我们看到一些我们感兴趣的几个属性。鉴于这篇文章的目的,我会讨论下这几个:

  • Function.prototype.length
  • Function.prototype.call
  • Function.prototype.apply

第一个是个属性,另外两个是方法。除了这三个,我还会愿意讨论下这个特殊的变量arguments,它和Function.prototype.arguments(已被弃用)稍有不同。

首先,我将定义一个“tester”函数来帮助我们弄清楚发生了什么。

这个函数简单记录了输入参数的值,和“上下文变量”,即this的值。
现在,让我们尝试一些事情:

我们注意到如果我们不输入第2、3个参数,程序将会显示它们为undefined(未定义)。此外,我们注意到这个函数默认的“上下文”是全局对象window。

使用Function.prototype.call

一个函数的 .call 方法以这样的方式调用这个函数,它把上下文变量this设置为第一个输入参数的值,然后其他的的参数一个跟一个的也传进函数。
语法:

因此,下面这两行是等效的:

当然,我们能够随需传入任何参数:

这个方法主要的功能是设置你所调用函数的this变量的值。

使用Function.prototype.apply

函数的.apply方法比.call更实用一些。和.call类似,.apply的调用方式也是把上下文变量this设置为输入参数序列中的第一个参数的值。输入参数序列的第二个参数也是最后一个,以数组(或者类数组对象)的方式传入。

语法:

因此,下面三行全部等效: