JavaScript 高级程序设计(第 3 版)中是这样介绍的:
There are two additional methods for functions: apply() and call(). These methods both call the function with a specific this value, effectively setting the value of the this object inside the function body.
ECMAScript5 defines an additional method called bind(). The bind() method creates a new function instance whose this value is bound to the value that was passed into bind().
每个函数都包含两个非继承而来的方法:apply() 和 call()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内 this 对象的值。
ECMAScript5 还定义了一个方法:bind()。这个方法会创建一个函数的实例,其 this 值会被绑定到传给 bind() 函数的值。
apply 与 call 的异同
相似处
作用一模一样,都是改变函数运行时的 this 指向。
不同处
主要区别在于传参的形式:
- apply 方法传入两个参数:作为函数上下文的对象,以及函数参数所组成的数组
- call 方法传入的第一个参数与 apply 方法相同,也是函数上下文的对象,但是后面传入的是一个参数列表,而不是单个数组
示例
let obj = {
age: 6
}
function func(name, favorite) {
console.log(`${name} is ${this.age} years old and he likes ${favorite} very much.`)
}
func.apply(obj, ['Peter', 'football']) // Peter is 6 years old and he likes football very much.
func.call(obj, 'Jack', 'basketball') // Jack is 6 years old and he likes basketball very much.
对比可看到,两个方法出了传参方式有所不同,作用是一样。在实际开发中,如果你的参数本来就存在一个数组中(如 arguments,当然这只是类数组),那自然就用 apply,如果参数比较散乱相互之间没什么关联,就用 call。
bind 与 apply、call 的异同
- bind() 方法是 ES5 中扩展的方法,并不兼容低版本的 IE 浏览器。
- bind() 与 call() 有些类似,接收的参数有两部分,第一部分是作为函数上下文的对象,第二部分传入的是参数列表。
- 但不同的是,bind() 返回的是一个改变了执行上下文 this 的函数,且不会立即执行,需要手动调用。
function func(a, b, c) {
console.log(a, b, c);
}
let func1 = func.bind(null, 'test');
func('A', 'B', 'C'); // A B C
func1('A', 'B', 'C'); // test A B
func1('B', 'C'); // test B C
func.call(null, 'test'); // test undefined undefined
call 是把第二个及以后的参数作为 func 方法的实参传进去,而 func1 方法的实参实则是在 bind 中参数的基础上再往后排。
原生实现 bind() 方法
if (!Function.prototype.bind) {
Function.prototype.bind = function () {
var self = this, // 保存原函数
context = [].shift.call(arguments), // 保存需要绑定的this上下文
args = [].slice.call(arguments); // 剩余的参数转为数组
return function () { // 返回一个新函数
self.apply(context,[].concat.call(args, [].slice.call(arguments)));
}
}
}
总结
三个方法相同点
- 都是用来改变函数的 this 对象的指向的
- 第一个参数都是 this 要指向的对象
- 都可以利用后续参数传参
三个方法不同点
- 三者的传参方式不同
- bind 的返回值是一个函数,需手动调用,而 apply 和 call 都是对函数的直接调用
网友评论