1.4.6 call, apply

用提供的对象来调用特定函数

call()apply() 使用给定的 this 值和参数来调用指定的函数。

  • Function.prototype.call()

  • Function.prototype.apply()

它两的功能几乎相同,只是参数不同。

// call() 接受参数列表
fn.call(this, 'apples', 'bananas'); 

// apply() 接受单个参数数组/类数组对象
fn.apply(this, ['apples', 'bananas']);
fn.apply(this, arguments);
fn.apply(this, {'length':2, '0':'eat', '1':'bananas'});

再配合函数的 arguments 参数和剩余参数 (...args) => {},以及展开语法 ...,这两个函数可以说是一模一样。文中的所有例子,call()apply() 都可以相互替代。

1. 语法

// call
call();
call(thisArg);
call(thisArg, arg1, /* …, */ argN);

// apply
apply(thisArg);
apply(thisArg, argsArray);
  1. 参数 thisArg:在调用函数时使用的 this

  2. 参数列表 arg1, ..., argN(可选),an argument list

  3. 参数数组或类数组 argsArray(可选),a single array of arguments

    • 类数组对象:有 length 属性,支持整数下标索引 []

  4. 返回值:使用指定的 this 值和参数调用函数的结果

对于一个现有的函数,我们可以给它分配一个不同的 this 对象来进行调用。

有了 call()apply(),一个对象的函数或方法就能被另外一个不同的对象来调用了,这样就能让我们只编写一次方法,然后在另一个对象中直接使用。

2. 常见用法

2.1 对象的构造函数

使用 call 可以链接到对象的构造函数(类似于 Java)。

以上代码,完成了 Food 和 Toy 对 Product 的继承。

2.2 调用函数

eg1. 调用函数,并指定上下文

eg2. 调用函数,且没有传第一个参数

eg3. 调用匿名函数

2.3 合并数组

我们可以使用 Array.prototype.push() 把一个或多个元素添加到数组的末尾。但如果给它传一个数组, push() 将会把这个数组作为一个整体(即单个元素),而不是依次添加数组里的元素。

而已有的 Array.prototype.concat() 是创建并返回一个新数组,而不是在现有的数组上追加。

在这种情况下,我们就可以使用 apply() 将数组隐式地“展开”成一系列的参数列表。

2.4 内置函数

巧妙地使用 apply() 可以让我们更灵活地使用内置函数。

需要注意的是,通过这种方式使用 apply()call(),可能会超出 JavaScript 引擎的参数长度限制,比如 JavaScriptCore 引擎的硬编码参数限制是 65536。所以若会超长,可以考虑先将数组分块。

3. 主要参考

Last updated