首先需要了解apply,call的基本用法,其目的是改变调用方法中的this指向,将其指向为传入的对象,改变this的指向,两种方法接收参数的方式不同。
代码:console.log
var console = window.console || {log: function () {}}; var log = console.log; console.log = function(tips,message){ Function.prototype.apply.call(log, console, arguments); //Function.prototype.call.call(log, console, arguments); //Function.prototype.call.apply(log, [console, arguments]); //传统方式 //var args=[].slice.call(arguments); //log.apply(console,args); }
执行结果:
console.log("测试","This is test");
测试 This is test
分析:
该怎么理解Function.prototype.apply.call(log,console,arguments);呢 首先可以将Function.prototype.apply看成一个整体-->FunctionApply FunctionApply.call(log,console,arguments); 那么将此句翻译一下 log.FunctionApply(console,arguments); 然后再翻译一下,你就懂了吧,就是一个普通方法调用了 console.log(arguments);
发散思维:
Function.prototype.call.apply(log,[console.arguments]);
FunctionCall.apply(log,[console,arguments]);
log.FunctionCall(console,arguments);
console.log(arguments);
小tips:
Function.prototype.apply.call 等同于Function.prototype.call.call
Function.prototype.call.apply 等同于 Function.prototype.apply.apply
免费外送个栗子:
function testA(a){ console.log('aaaa',a); } Function.prototype.apply.call(testA,window,['Mike']); //Function.prototype.call.call(testA,window,['Mike']); //testA.apply(window,['Mike']); //window.testA('Mike'); //Function.prototype.apply.apply(testA,[window,['Mike']]); //Function.prototype.call.apply(testA,[window,['Mike']]);
以上执行结果都一样
为:aaaa Mike
总结使用用法:
XXX可以是call或者是apply,child一定是parent可指向的对象
Function.prototype.XXX.call(child,parent,arguments||array);
Function.prototype.XXX.apply(child,[parent,arguments||array]);
--------------------------------------------------------------------------------------------------------------------------------------------------------------
终极方法
Function.prototype.apply.call(console.log,console,arguments);
这么一对比,第三种方案妥妥的胜出啊,不用考虑兼容,代码简短,虽然不是很好理解~~
说了这么多废话,Function.prototype.apply.call什么时候用,就是在这种应用场景。
如果还有其他的话,那就是那些奇葩面试题,比如:
var f1=function(){console.log(1)}; var f2=function(){console.log(2)}; Function.prototype.call.call(Function.prototype.call,f2)//2 Function.prototype.call.call(f1,f2);//1
------------------------------------------------------------------------------------------------------------
根据 call 方法的调用规则,Function.prototype.apply.call( fn, thisArg, args ) 中的第一个参数 fn,将作为 Function.prototype.apply(以下简称为: apply) 中 this 的值,剩余的两个参数 thisArg 和 args 都将被传递给 apply。
(为便于以下的说明,我们先来看一下 apply 的正常使用方式:fn.apply( thisArg, args ),也就是说,我们要通过 apply 的方式来调用函数 fn,此时 fn 中 this 的值为 apply 的第一个参数 thisArg, apply 的第二个参数 args 则被传递给了 fn,从而实现对 fn 的调用。然而,这里有一个要点,一般来说,我们都不会太去关注,那就是,apply 方法中的 this 此时应该指向哪个值呢?没错,应该指向 fn。好了,我们继续往下看)
虽然我们对 apply 的具体实现细节不清楚,但可以肯定的是,apply 中 this 的值即是要通过 apply 的方式来调用的函数(在此例中为 fn)。既然已经知道要通过 apply 方法来调用 fn,那么我们继续往下看:
根据 apply 方法的调用规则,在此例中,传递给 apply 方法的第一个参数 thisArg 将作为 fn 中 this 的值,第二个参数 args 将被传递给 fn,从而实现对 fn 的调用。到这里我们就可以看到 Function.prototype.apply.call( fn, thisArg, args ) 这个调用其实等价于 fn.apply( thisArg, args ) 这个调用。