前言
javascript是动态编程语言,存在创建时上下文,运行时上下文,并且这些上下文都是可以动态改变的。而call,apply和bind的作用就是动态的改变上下文。
call、apply和bind的作用都差不多,只是使用上有点小区别。
call和apply
call,apply都属于Function.prototype
的一个方法,他是javascript引擎内在实现的,因为属于Function.prototype
,所以每个Function对象实例,都有call,apply属性。其实他们的作用是一样的,只是传递的参数不一样而已。
- apply:接受2个参数,第一个参数指定了函数体内this对象的指向,第二个参数为数组或者一个类数组。apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入。
- call:接受2个参数,第一个参数指定了函数体内this对象的指向,后边的参数是函数调用时的参数按顺序传递。
举个例子:
1 | let obj1 = { |
1 | function showArgs(a, b, c){ |
面试题:定义一个 log 方法,让它可以代理 console.log 方法:
去面试的时候,面试官问我怎么使用传进去的参数,我说直接使用,他说不对,是通过一个arguments数组
1 | // 常规做法 |
bind
bind方法与apply和call很相似,也是可以改变函数体内this的指向。
MDN的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
举个例子:
1 | var func = function(){ |
- 在Javascript中,多次 bind() 是无效的。更深层次的原因, bind() 的实现,相当于使用函数在内部包了一个 call / apply ,第二次 bind() 相当于再包住第一次 bind() ,故第二次以后的 bind 是无法生效的。
这三个方法的异同
举个例子:
1 | var obj = { |
看到bind后面对了一对括号。区别是,当你希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用 bind() 方法。而 apply/call 则会立即执行函数。
总结
apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
apply 、 call 、bind 三者都可以利用后续参数传参;
bind是返回对应函数,便于稍后调用;apply、call则是立即调用 。
实现apply、call(简化版)
- 将函数设为对象的属性
- 执行该函数
- 删除该函数
1 | //call |
1 | //apply |
实现bind(简化版)
bind函数有两个特点:
- 返回一个函数
- 可以传入参数
返回函数模拟实现
修改this指向,可以使用call或者apply实现
1 | Function.prototype.bind2 = function (context) { |
传参模拟实现
1 | Function.prototype.bind2 = function (context) { |
示例
1 | var foo = { |
Reference – 前端基础:call,apply,bind的的理解