共计 1816 个字符,预计需要花费 5 分钟才能阅读完成。
问题由来:当我看到这句代码的时候
Function.prototype.apply.call(Math.floor, undefined, [1.75])
普通人的第一反应:执行 Math.floor.apply(undefined,[1.75])
OK, 你为什么会觉得是这样执行?
会不会是因为代码中,恰巧给你标记好了 undefined,让你有的答案?
那么假如代码本身是这样子:
Function.prototype.apply.call(undefined,Math.floor, [1.75])
或者
Function.prototype.apply.call(Math.floor, Math.ceil, [1.75])
这时候,你是不是也能立刻给出答案?
反正我是没有立马搞清楚。
那么事实究竟如何?
call 和 apply 不是很简单嘛,无非就是改变 this 指向,然后 aplly 传参为数组罢了。
对,它们就是这么简单。
看看源码
// ES3 call 实现
Function.prototype.es3call = function (context) {
var content = context || window;
content.fn = this;// 注意这一行
var args = [];
// arguments 是传入的参数 (实参) 的类数组对象 函数自带
for (var i = 1, len = arguments.length ; i < len; i++) {args.push('arguments[' + i + ']');
}
var result = eval('content.fn('+args+')');// 注意这一行
delete content.fn;
return result;
}
// ES3 apply 实现
Function.prototype.es3apply = function (context, arr) {
var context = context || window;
context.fn = this;// 注意这一行
var result;
if (!arr) {result = context.fn();
} else {
// 获取参数
var args = [];
for (var i = 0, len = arr.length; i < len; i++) {args.push('arr[' + i + ']');
}
// 执行函数
result = eval('context.fn(' + args + ')')// 注意这一行
}
delete context.fn;
return result
}
其中有两行需要注意:
1、context.fn=this
2、result=eval(‘context.fn(‘ + args + ‘)’)
可以看出 call 和 apply 做了两件很重要的事:
1、代码在给 context 绑定 this,而我们都知道,this 指向的是当前执行上下文
比如:
function test(){}
test.call()
由于是由 test 调用的 call 方法,因此,this 指向的是 test
2、代码 context.fn(),无非就是 this()
那么上面的代码
Function.prototype.apply.call(Math.floor, undefined, [1.75])
正确打开方式:
1、Function.prototype.apply 本身就是一个函数,相当于 test,我们给它起个昵称 FunctionApply,相当于
FunctionApply.call(Math.floor, undefined, [1.75])
2、call 方法无非就是在给 FunctionApply 绑定 this 指向 Math.floor
牢记
FunctionApply(Function.prototype.apply) 的 this 指向 Math.floor
牢记
FunctionApply(Function.prototype.apply) 的 this 指向 Math.floor
牢记
FunctionApply(Function.prototype.apply) 的 this 指向 Math.floor
相当于执行
Function.prototype.apply(undefined, [1.75])
这不就是一个普通函数执行嘛。
但是别忘了刚刚提到的。
call 和 apply 做了两件最重要的事情:
1、绑定 this
2、this()
而 Function.prototype.apply 的 this 指向的 Math.floor
因此最终才是执行的 Math.floor(1.75)