dojo.hitch与dojo.partial函数就是通过apply函数来实现的,其本质就是改变了函数中this变量(指针)的指向,两个函数都会重新返回一个函数,返回的函数this变量被第一个参数替换。
dojo.hitch函数源码如下:
dojo._hitchArgs = function(scope, method /*,...*/){
//排除第一个和第二个参数后转成一个数组,其实就是将method后面的参数作为目标函数的参数,转成一个数组
var pre = d._toArray(arguments, 2);
//method是否是字符串类型
var named = d.isString(method);
//返回一个新函数
return function(){
//将这个新函数的的arguments转成数组,注意上下这两个arguments对象是不同的,上一个是属于dojo_hitchArgs函数,下一个是属性于返回的新函数的
var args = d._toArray(arguments);
//取出目标函数,如果scope不存在,则函数为window[method]
var f = named ? (scope||d.global)[method] : method;
//将两个参数数组进行连接,形成完整参数数组,这就是为什么通过hitch函数,参数可以分两次传递的原因
//这个新函数的返回值就是目标函数执行的返回值,只是this变量进行了替换
return f && f.apply(scope || this, pre.concat(args)); // mixed
}; // Function
};
dojo.hitch = function(/*Object*/scope, /*Function|String*/method /*,...*/){
//scope就是用于替换this变量的对象;method可以是一个字符串,或者是一个函数,用于指明替换哪个函数的this变量
if(arguments.length > 2){
//如果参数个数多于两个则,调用dojo._hitchArgs函数
return d._hitchArgs.apply(d, arguments); // Function
}
//如果method未指定
if(!method){
method = scope;
scope = null;
}
//如果method是字符串类型
if(d.isString(method)){
//如果scope不存在则,scope为全局对象,即window
scope = scope || d.global;
if(!scope[method]){ throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); }
//返回一个新函数,该函数调用scope[method]函数,并使this指向scope
return function(){ return scope[method].apply(scope, arguments || []); }; // Function
}
//如果scope不存在,则直接返回该函数,这时并没有修改this变量
//如果scope存在,则直接调用该函数,并使this指向scope
return !scope ? method : function(){ return method.apply(scope, arguments || []); }; // Function
};
此时,在形式3的基础上对参数进行连接
dojo.partial = function(/*Function|String*/method /*, ...*/){
var arr = [ null ];
//将scope置为null
return d.hitch.apply(d, arr.concat(d._toArray(arguments))); // Function
};
function bar(a, b, c) {
console.info("a=" + a + ",b=" + b + ",c=" + c);
}
var fn = dojo.hitch(window, "bar", 1, 2);
fn(3); //a=1, b=2, c=3。参数只能分两次进行传递
fn = dojo.partial(bar, 1);
fn = dojo.partial(fn, 2);
fn(3); //a=1, b=2, c=3。参数可以分多次进行传递
fn = dojo.partial(fn, 3);
fn(); //a=1, b=2, c=3。参数可以分多次进行传递