问题由来:当我看到这句代码的时候
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)