在上一篇 JavaScript函数的属性和方法 中提到了函数的三个方法call() apply() bind() 三个方法.
索源
call,apply,bind这三个方法其实都是继承自Function.prototype中的,属于实例方法。1
2
3console.log(Function.prototype.hasOwnProperty('call')) // true
console.log(Function.prototype.hasOwnProperty('apply')) // true
console.log(Function.prototype.hasOwnProperty('bind')) // true
上面代码中,都返回了true,表明三种方法都是继承自Function.prototype的。当然,普通的对象,函数,数组都继承了Function.prototype对象中的三个方法,所以这三个方法都可以在对象,数组,函数中使用。
call方法
函数实例的call方法,可以指定该函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。并且会立即执行该函数。
1 | var teacher = { |
上面代码中,person函数中的this关键字,如果指向全局对象,返回结果为Felix。可以看到,如果call方法没有参数,或者参数为null或undefined或者this,则等同于指向全局对象。如果使用call方法将this关键字指向teacher对象,也就是将该函数执行时所在的作用域为teacher对象,返回结果为up8。
call()方法可以传递两个参数。第一个参数是指定函数内部中this的指向(也就是函数执行时所在的作用域),第二个参数是函数调用时需要传递的参数。
1 | function add(x, y) { |
第一个参数是必须的,可以是null,undefined,this,但是不能为空。设置为null,undefined,this表明函数add此时处于全局作用域。第二个参数中必须一个个添加。而在apply中必须以数组的形式添加。
apply方法
apply方法的作用与call方法类似,也是改变this指向(函数执行时所在的作用域),然后在指定的作用域中,调用该函数。同时也会立即执行该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数。
apply方法的第一个参数与call的第一个参数一样,也是this所要指向的那个对象,如果设为null或undefined或者this,则等同于指定全局对象。第二个参数则是一个数组,该数组的所有成员依次作为参数,在调用时传入原函数。原函数的参数,在call方法中必须一个个添加,但是在apply方法中,必须以数组形式添加。
1 | function add(x, y) { |
bind方法
bind方法用于指定函数内部的this指向(执行时所在的作用域),然后返回一个新函数。bind方法并非立即执行一个函数1
2
3
4
5
6
7var person = {
name: 'Felix Cao',
getName: function() {
console.log('this.name: ', this.name);
}
}
person.getName();
上面代码中,this.name指向person对象的内部属性name,如果把person对象的getName方法赋值给另外一个变量,调用执行后就不是期望的结果
1 | var person = { |
为什么呢?在JavaScript中的this绑定/指向这篇文章中 提到 隐式绑定中的上下文丢失, 为了解决这个问题,可以使用bind方法,将person对象里的this绑定到person对象上,或者是直接调用。
1 | var personName = person.getName.bind(person); |
上面的代码中,可以看出call, apply, bind三者的区别: call和apply方法都是在调用之后立即执行的。而bind调用之后是返回原函数, 需要再调用一次才行,有点像是闭包的玩法。
有必要总结一下
- 第一个参数都是指定函数内部中this的指向(函数执行时所在的作用域),然后根据指定的作用域,调用该函数。
- 都可以在函数调用时传递参数。call,bind方法需要直接传入,而apply方法需要以数组的形式传入。
- call,apply方法是在调用之后立即执行函数,而bind方法没有立即执行,需要将函数再执行一遍。有点闭包的味道。
- 改变this对象的指向问题不仅有call,apply,bind方法,也可以使用that变量来固定this的指向。