Dojo学习笔记七:Making Functions with hitch and partial

dojo/_base/lang包含两个有用的方法:lang.hitch和lang.partial。lang.hitch主要负责修改this运行上下文,lang.partial主要负责修改函数参数个数,进行函数签名。

1、JavaScript 中的运行上下文(execution contexts)

在JavaScript中,当一个函数调用一个运行上下文就被创建出来。上下文的创建经过如下阶段:

(1)arguments 参数对象的创建;

(2)函数作用域 scope 的创建;

(3)函数中变量 Variables 的实例化;

(4)this 属性(指向上下文 context 自身) 的创建。

this 属性是绝大多数开发者都会混淆的地方;它其实就是一个指向函数调用时作为上下文context(或叫作用域 scope)的对象的引用,在 JavaScript 中,函数执行时的实际上下文,是在函数调用时才决定的。

作用域 (scope),它就是个对象,既可以作为方法函数调用执行时的空间,也可以作为方法函数属性等的定义空间。后面会讲到词法作用域(lexical scope),可以认为为这是 JavaScript 中真正的作用域,词法作用域使用了闭包技术closures。

函数调用时的作用域(scope) ,在JavaScript中称为运行上下文(execution context)。

<!DOCTYPEhtml>
<html>
<head>
<Metacharset="UTF-8">
<title>dojoConfig</title>
<styletype="text/css">
.myNode{
border:1pxsolid#999;
margin:0.5em;
padding:0.5em;
background-color:#ccc;
float:left;
}
</style>
<scriptsrc="dojo/dojo.js"></script>
<script>
//Retrievethedependencies
require(["dojo/query","dojo/dom-construct","dojo/domready!"],function(query,domConstruct){
functionlog(msg){
varc=document.getElementById("console");
if(!c){
c=domConstruct.create("div",{
id:"console"
},document.body);
}
c.innerHTML+="<div>"+msg+"</div>";
}
varmyObject={
foo:"bar",myHandler:function(evt){
//stillcontrived!
//假设evt为事件对象:W3C标准中,使用evt.target,而IE为evt.srcElement
log("Thevalueoffoois"+this.foo+",from"+(evt&&evt.target?evt.target.id:window.event.srcElement.id));
}
};
varcontainer=document.getElementById("nodeContainer");
for(vari=0;i<5;i++){
domConstruct.create("div",{
id:"node-"+(i+1),className:"myNode",innerHTML:"Fakebutton"+(i+1)
},container);
}
query(".myNode").forEach(function(node){
node.onclick=myObject.myHandler;
});
});
</script>
</head>
<body>
<divid="nodeContainer">
</div>
</body>
</html>

输出结果:

The value of foo is undefined,from node-1

The value of foo is undefined,from node-2

The value of foo is undefined,from node-3

分析原因:

期望的结果是显示显示"The value of 'foo' is bar",但我们得到信息:The value of 'foo' is undefined。

(1)node.onclick = myObject.myHandler

在这里 myObject.myHandler 经过解析,变成了函数 myHandler,仅仅是函数而已。而 myHandler 做为 myObject 的方法的这一事实被完全舍弃了。(将 myObject.myHandler 赋值给 onclick , context 什么事儿,它才不管这个函数在哪定义,他完全将这个函数同对象本身剥离了。)

(2)如果你依然困惑,只需要记住在 JavaScript中 Functions objects同其他非原始类型一样,是引用传递,而非值传递。在我们上面的例子中,我们不过将 onclick 设置为一个直接指向 myObject.myHandler的引用。

使用.apply和.call切换运行上下文execution contexts

query(".myNode").forEach(function(node){
node.onclick=function(evt){
myObject.myHandler.call(myObject,evt);
};
});

将触发绑定事件代码修改成如上内容,就可得到想要的结果。

(1)使用lang.hitch绑定运行上下文execution context

<!DOCTYPEhtml>
<html>
<head>
<Metacharset="UTF-8">
<title>dojoConfig</title>
<styletype="text/css">
.myNode{
border:1pxsolid#999;
margin:0.5em;
padding:0.5em;
background-color:#ccc;
float:left;
}
</style>
<scriptsrc="dojo/dojo.js"></script>
<script>
//Retrievethedependencies
require(["dojo/_base/lang","dojo/query",function(lang,query,myHandler:function(evt){
//stillcontrived!
log("Thevalueoffoois"+this.foo+",container);
}
query(".myNode").forEach(function(node){
node.onclick=lang.hitch(myObject,myObject.myHandler);
});
});
</script>
</head>
<body>
<divid="nodeContainer">
</div>
</body>
</html>

说明:

lang.hitch可以指定函数的上下文,关键代码

query(".myNode").forEach(function(node){
node.onclick=lang.hitch(myObject,myObject.myHandler);
});

(2)参数对象The arguments object

arguments object 并非一个真正的JavaScript的Array object;尽管某些方面同数组类似(如采用数字下标索引,包含 length 属性等),但其是只读的,因此某些 Array 方法对其无效(如 Array.prototype.slice)。

(3)使用lang.partial修改函数签名function signatures

query(".myNode").forEach(function(node){
//don'tforget:methodfirst,fixedargumentssecond!
node.onclick=lang.partial(myObject.myHandler,myObject);
});

(4)将 hitch和partial 的优点整合在一起

是不是很想把 htich 的优点(强制运行上下文)和partial的优点(预置参数)整合在一起?好吧,lang.hitch进一步增强可以完成以上两种工作:你可以在context和method 两个参数后,再添加任意数量的参数,lang.hitch 将会绑定上下文,预置参数,生成新的函数


备注:hitch和partial 是通往函数式编程的入口(参考:functional programming);Dojo Toolkit 在dojox/lang/functional下提供了很多函数式编程技术东西,建议你有空看看。

相关文章

我有一个网格,可以根据更大的树结构编辑小块数据.为了更容易...
我即将开始开发一款教育性的视频游戏.我已经决定以一种我可以...
我正在使用带有Grails2.3.9的Dojo1.9.DojoNumberTextBox小部...
1.引言鉴于个人需求的转变,本系列将记录自学arcgisapiforja...
我正在阅读使用dojo’sdeclare进行类创建的语法.描述令人困惑...
我的团队由更多的java人员和JavaScript经验丰富组成.我知道这...