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。参数可以分多次进行传递