call和apply这两个方法都可以改变一个函数的上下文对象,只是接受参数的方式不一样,调用时会直接触发函数。
call接收的是逗号分隔的参数。
apply接收的是参数列表。
bind也可以改变函数的上下文对象,接收的是逗号分隔的参数,但是不会立刻触发函数,只会创建一个新的函数,在调用时设置this关键字为提供的值
例如
var arr = [1, 2, 3]; var max = Function.prototype.apply.call(Math.max, null, arr); console.log(max); // 3
那么对这段代码怎么理解呢?
1. 将Function.prototype.apply看成一个整体
(Function.prototype.apply).call(Math.max, null, arr)
2. func.call(context, args)可以转化为context.func(args)
所以代码被转换为:
Math.max.apply(undefined, arr)
如果将call和apply交换位置呢
var arr = [1, 2, 3]; var max = Function.prototype.call.apply(Math.max, null, arr); console.log(max); // -Infinity
为什么的它的输出结果为-Infinity呢?
因为apply的第二参数必须为数组,这里并不是,所以参数不能正确的传递给call函数。
根据func.apply(context, args)可以转化为context.func(args)。所以被转化成了Math.max.call(), 直接调用则会输出-Infinity。
如果想要正确调用,则应这样书写:
var arr = [1, 2, 3]; var max = Function.prototype.call.apply(Math.max, arr); console.log(max); // 3
这里有一道面试题来巩固下
var a = Function.prototype.call.apply(function(a){return a;}, [0,4,3]); alert(a);
分析下
// 将call方法看成一个整体 (Function.prototype.call).apply(function(a){return a;}, [0,4,3]); // func.apply(context, args)可以转化为context.func(...args) (function(a){return a;}).call(0, 4, 3); // 所以结果很明显,输出4
bind则和call的用法差不多,唯一区别是,call会立刻调用函数,bind只是绑定this
var arr = [1, 2, 3]; console.log(Math.max.call(...arr)); // 3 console.log(Math.max.bind(...arr)()) // 3