写给新人的 call、apply、bind

avatar
全栈开发工程师 @京东

1、call()

语法:

fun.call(thisArg[, arg1[, arg2[, ...]]])

thisArg:fun函数运行时指定的this值,可能的值为:

  • 不传,或者传null,undefined, this指向window对象
  • 传递另一个函数的函数名fun2,this指向函数fun2的引用
  • 值为原始值(数字,字符串,布尔值),this会指向该原始值的自动包装对象,如 String、Number、Boolean
  • 传递一个对象,函数中的this指向这个对象

例如:

function a(){
    console.log(this);
    function b(){}
    a.call(b);  

经常会看到这种使用情况:

function list() {
  return Array.prototype.slice.call(arguments);  
  list(1,2,3);  

为什么能实现这样的功能将arguments转成数组?首先call了之后,this指向了所传进去的arguments。我们可以假设slice方法的内部实现是这样子的:创建一个新数组,然后for循环遍历this,将this[i]一个个地赋值给新数组,最后返回该新数组。因此也就可以理解能实现这样的功能了。

2、apply()

语法:

fun.apply(thisArg[, argsArray])

例如:

var numbers = [5, 6, 2, 3, 7];
var max = Math.max.apply(null, numbers);
console.log(max)  // 7

平时Math.max只能这样子用:Math.max(5,6,2,3,7);
利用apply的第二个参数是数组的特性,从而能够简便地从数组中找到最大值。

3、bind

基本用法

语法:

fun.bind(thisArg[, arg1[, arg2[, ...]]]);

bind()方法会创建一个新函数,称为绑定函数。 bind是ES5新增的一个方法,不会执行对应的函数(call或apply会自动执行对应的函数),而是返回对绑定函数的引用。 当调用这个绑定函数时,thisArg参数作为 this,第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。 简单地说,bind会产生一个新的函数,这个函数可以有预设的参数。

function list() {
  return Array.prototype.slice.call(arguments);  
  var leadingThirtysevenList = list.bind(undefined, 37); 
var list = leadingThirtysevenList(1, 2, 3); 
console.log(list); 

bind调用简单

把类数组换成真正的数组,bind能够更简单地使用:

var slice = Array.prototype.slice;
slice.apply(arguments);  
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.apply.bind(unboundSlice);
slice(arguments);  

4、它们的区别

相同之处:改变函数体内 this 的指向。
不同之处:

  • call、apply的区别:接受参数的方式不一样。
  • bind:不立即执行。而apply、call 立即执行。

5、参考

www.cnblogs.com/coco1s/p/48…
segmentfault.com/a/119000000…
segmentfault.com/a/119000000…
www.cnblogs.com/coco1s/p/48…