javascript函数方法:call、apply和bind

205 阅读3分钟

前言

最近在读《javascript高级程序设计》疏通经脉,通过写文的方式加强自己理解。

函数方法

在前端面试的问题中少不了this指向的问题,而以下三种方法都可以改变this指向:

  1. apply()
  2. call()
  3. bind()

1. apply方法

apply()call()两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内的this对象的值apply()方法接受两个参数:

  • 第一个参数:thisArg

thisArg该参数可选填,在 func 函数运行时使用的 this 值。如果这个函数处于非严格模式下,则指定为nullundefined 时会自动替换为指向全局对象,原始值会被包装。如果该参数缺失时则指向全局对象

  • 第二个参数: argsArray

argsArray该参数可选填,接受一个数组或arguments(arguments知识传送门:javascript:函数属性梳理)。如果不填写则代表不需要传参。

  let o1 = {
    number: 100
  }
  let o2 = {
    number: 200
  }
  function sum (num1, num2) {
    console.log(num1 + num2 + this.number)
  }
  sum.apply(o1, [1, 10]) //    111    将this指向o1
  sum.apply(o2, [1, 10]) //    211    将this指向o2

apply()不仅能传参,最重要的是能够改变函数赖以运行的作用域!!!在上面的例子中,当传入o1时,this.number指向了o1里的number;当传入o2时,this.number指向了o2里的number

2. call方法

理解了apply(),那理解call()便不费吹灰之力。因为call()apply()方法唯一的区别在于第二个参 接受参数的形式不同作用完全相同。call()传递给函数的参数只能逐个列举出来,看下面的例子:

  function sum (num1, num2) {
    console.log(num1 + num2)
  }
  sum.call(o1, 1, 10)  //  11

3. bind方法

bind()方法创建一个新的函数,在调用时设置this关键字为提供的值。并在调用新函数时,将给定参数列表作为原函数的参数序列的前若干项。和call()apply()的区别在于:bind()会创建一个原函数的拷贝(绑定函数),拥有指定的this值和初始参数,并返回这个函数。看下MDN里的描述:

bind() 最简单的用法是创建一个函数,不论怎么调用,这个函数都有同样的 this 值。JavaScript新手经常犯的一个错误是将一个方法从对象中拿出来,然后再调用,期望方法中的 this 是原来的对象(比如在回调中传入这个方法)。如果不做特殊处理的话,一般会丢失原来的对象。基于这个函数,用原始的对象创建一个绑定函数,巧妙地解决了这个问题:

this.x = 9;    // 在浏览器中,this指向全局的 "window" 对象
var module = {
  x: 81,
  getX: function() { return this.x; }
};

module.getX(); // 81

var retrieveX = module.getX;
retrieveX();   
// 返回9 - 因为函数是在全局作用域中调用的

// 创建一个新函数,把 'this' 绑定到 module 对象
// 新手可能会将全局变量 x 与 module 的属性 x 混淆
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81

结语

关于call、apply和bind函数的作用极其相似,但有不同之处,关于如何更好运用还得在探索。

参考资料:

  • 《javascript高级程序设计》
  • MDN--bind

种一棵树最好的时间是十年前。