前言 要理解hitch与partial函数,前提是需要理解函数中的this变量。在javascript函数中,this变量其实是函数执行上下文(Execution Context)的一个属性,这函数是哪个对象的 属性,则this指向的就
前言
要理解hitch与partial函数,前提是需要理解函数中的this变量。在javascript函数中,this变量其实是函数执行上下文(Execution Context)的一个属性,这函数是哪个对象的 属性,则this指向的就是函数所属的那个对象;比如:全局函数与匿名函数中this指向的是全局对象window(浏览器环境中);someObj.someFunc();someFunc()函数中的this指向的是someObj这个对象。 不过这是一般情况下,其实任何对象都可以作为函数中的this对象,可以通过Function.prototype.call与Function.prototype.apply这个函数来改变this变量的指向;call与apply实现的功能是一样的,只是参数形式不一样,具体可以百度一下。在很多js框架中都喜欢把this变量取名scope(作用域),但个人认识不是很合适,js中作用域与this完全是两码事,不过理解this变量就好,名字只是个代号而已。 dojo.hitch与dojo.partial函数就是通过apply函数来实现的,其本质就是改变了函数中this变量(指针)的指向,两个函数都会重新返回一个函数,返回的函数this变量被第一个参数替换。
dojo.hitch
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 };
通过上述的解析可以知道,hitch函数可以有如下调用形式:
1. method为字符串且不传递额外参数:
a. scope不存在,scope为window对象
b. scope存在,则scope不变
返回的函数调用scope[method]函数,this指向scope对象;
2. method为字符串且传递额外参数:
此时,在形式1的基础上对参数进行连接
3. method为函数且不传递额外参数:
a. scope不存在,则直接返回该函数,这时并没有修改this变量
b. scope存在,返回一个新函数,该函数调用method,this指向scope对象
4. method为函数且传递额外参数
此时,在形式3的基础上对参数进行连接
dojo.partial
源码如下:dojo.partial = function(/*Function|String*/method /*, ...*/){ var arr = [ null ]; //将scope置为null return d.hitch.apply(d, arr.concat(d._toArray(arguments))); // Function };
可以看到,partial是基于hitch函数实现的,而且很像,只不过相对于hitch函数,partial将scope置为了null而已,所以
dojo.partial(method)等价于dojo.hitch(null, method)。partial与hitch有个区别是在给函数传递参数时,hitch函数最多分两传递参数,而partial可以分多次,其原因就是因为调用partial函数时scope为空,具体请看hitch函数调用形式。下面是一个具体例子:
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。参数可以分多次进行传递
PS:dojo版本为dojo-release-1.6.3