今天在读cw_logger源码的时候,看到这么一个方法:
Function.prototype.apply.call
顿时,觉得难道还能这么调用。为什么?
1. 先来看看上下文
if (context === MyLogger.WARN && console.warn) {
hdlr = console.warn;
} else if (context === MyLogger.ERROR && console.error) {
hdlr = console.error;
}
}
invokeConsoleMethod(hdlr, messages) {
let moduleStr = "[" + this.logOwner + "]";
Function.prototype.apply.call(hdlr, console, [moduleStr, messages]);
}
参数说明:
hdlr : 是外部传进来的函数
message : 提示信息
其他说明 :
console , 就是浏览器的console
2. 再看call
先来复习定义:
fun.call(thisArg, arg1, arg2, ...)
thisArg
在fun函数运行时指定的this值。需要注意的是,指定的this值并不一定是该函数执行时真正的this值,如果这个函数处于非严格模式下,则指定为null和undefined的this值会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象。
arg1, arg2, …
指定的参数列表。
PS:
fun.apply(obj,args)等价于obj.fun(args),这一步是重点,必须理解。
call接受的是一个参数列表。
(Function.prototype.apply).call(hdlr, console, [moduleStr, messages]);
hdlr 将函数运行的上下文,指向了console.error或者console.warn。
相当于:
hdlr.apply(console, [moduleStr, messages]);
3.再看apply
先来看看apply的定义
func.apply(thisArg, [argsArray])
thisArg
可选的。在 func 函数运行时使用的 this 值。需要注意的是,使用的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动替换为指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的包装对象。
argsArray
可选的。++==一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func 函数==++。如果该参数的值为null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。浏览器兼容性请参阅本文底部内容。
举个例子:
var numbers = [5, 6, 2, 3, 7];
/* using Math.min/Math.max apply */
var max = Math.max.apply(null, numbers);
于是乎:
hdlr.apply(console, [moduleStr, messages]);
相当于:
hdlr(moduleStr, messages);
就相当于:
console.error(moduleStr, messages);
4.来道考题
var b = Function.prototype.call.apply(function(a){return a;}, [0,4,3]);
alert(b);
结果:
b = 4;
按照上面的解释,apply的代码会变成这样:
b = (function(a){return a;}).call(0,4,3)
结果:
b = 4
5.总结
不管是call
在前,还是apply
在前。只要是以Function.prototype.call
形式被调用,他们都会将函数的上下文指向第一个参数。如果后面没有更改,那么就会一直指向那个上下文。
当然如果第一个参数是一个指定的值或者null、undefined
,而不是一个具体的对象,那么上下文环境不发生改变。
至于call后面还可以调用apply或者反之,因为都在原型链上,这很容易理解。
参考文章
call的定义
apply的定义