underscore源码中,很多地方用到call和apply两个函数
call和apply都是函数的方法
JavaScript中通过call或者apply用来代替另一个对象调用一个方法,即改变函数运行的上下文
更直接点说,就是改变函数中’this’关键字的指向

call

用法:

call(obj,arg1,arg2,arg3);
其中obj参数为将要调用函数的对象,arg1…..argn为传入的参数。 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var func = {
name : '我是内部名字',
log : function(){
console.log(this.name);
}
}
var name = '我是外部名字';

func.log(); //=> 我是内部名字;
func.log.call(this); //=>我是外部名字
func.log.call(window); //=> 我是外部名字
func.log.call(); //=> 我是外部名字
func.log.call(null); //=> 我是外部名字
func.log.call(undefined); //=> 我是外部名字

在ES5中规定严格模式下,call的obj参数为null和undefined时不会被替换为全局变量window

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(function(){
'use strict';
var func = {
name : '我是内部名字',
log : function(){
console.log(this.name);
}
}
var name = '我是外部名字';

func.log(); //=> 我是内部名字;
func.log.call(window); //=> 我是外部名字
func.log.call(); //=> 报错
func.log.call(null); //=> 报错
func.log.call(undefined); //=> 报错
})();

apply

apply的功能同call是一样的,不同的是在参数上:

apply(obj,[arg1,arg2,arg3,…]);
其中obj参数为将要调用函数的对象,第二个参数为传入的参数数组。

underscore中的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
根据传入的函数,生成不同的有效的函数,供后面的其他函数调用   
var optimizeCb = function(func, context, argCount) {
if (context === void 0) return func; //context判断使用了 void 0的形式,当context未传入参数时,直接返回func;但是若context传入的是null,则继续执行;
switch (argCount == null ? 3 : argCount) {
case 1:
return function(value) {
return func.call(context, value); //null值在 call 和apply中传入的时候,是怎么处理的?
//......ES5中规定,非严格模式下,当call的第一个参数为null或者undefined时,将默认使用window(浏览器)或者global(node)执行;严格模式下,不作转换;
//......此处未使用严格模式,当context为null时,替换为全局window或global执行;
};
case 2:
return function(value, other) {
return func.call(context, value, other);
};
case 3:
return function(value, index, collection) {
return func.call(context, value, index, collection);
};
case 4:
return function(accumulator, value, index, collection) {
return func.call(context, accumulator, value, index, collection);
};
}
return function() {
return func.apply(context, arguments);
};
};

本文地址: http://gehaiqing.com/2016/08/17/js-underscore-call-apply/