JavaScript 学习笔记 8_AJAX事件处理和函数上下文

Ajax事件处理和函数上下文

对于鼠标和键盘事件的特殊种类来说,Ajax事件处理函数和大多数GUI工具包语言(GUI toolkit language) 中的事件处理函数差不多是一样的。现在关注一个经常使粗心的开发者犯错的特定问题。

事件处理函数要么当作HTML标记一部分来声明,例如:
<div id = ‘myDiv’ onclick = ‘alert:alert(this.id)’ ></div>

或者使用编程方式来声明,例如:
function clickHandler() { alert(this.id); }
myDiv.onclick = clickHandler;

注:在编程方式下,我们传递的是一个对Function对象的引用(在clickHandler后面没有())。在HTML中声明函数中,我们有效地以内嵌方式声明了一个匿名函数,等同于:
myDiv.onclick = function() { alert(this.id); }

注意,在两种情况下,都没有为函数分配参数,也没有任何方式可以便随鼠标的点击传递参数。然而,当点击DOM元素的时候,Event对象作为了函数调用的参数,元素本身作为上下文对象。知道这一点可以大大减少麻烦和困惑,特别是当你在编写面向对象的代码时。混乱的关键之源在于DOM节点总是作为上下文来传递,甚至在函数附加到一个不同对象的原型上的时候。

来看一个问题:

function myObj(id,div)
{
this.id = id;
this.div = div;
this.div.onclick = this.clickHandler;
}

myObj.prototype.clickHandler = function(event)
{
alert(this.id);
}

当我们点击GUI元素的时候,它将显示那个对象的ID,这个判断对吗?事实上,它并没有这样做,因为myObj.clickHandler函数将会被浏览器借用,并且在那个元素的上下文中调用,而不是在模型对象的上下文中。

因为元素碰巧也有一个内建的id属性,它将会显示一个值,并且依赖于命名约定,这个值甚至可以与模型对象的ID相同。

好了,现在如果希望事件处理函数引用它附加到的模型对象,我们需要使用另外一种方式将那个对象的引用传递进来。下面将介绍两种方法。

使用名称引用模型

策略:给模型对象的每一个实例分配全局唯一的ID,并且维护一个通过ID来引用的这些对象的全局数组。
假设我们得到了一个对DOM元素的引用,随后就可以通过使用ID的一部分作为查找数组(lookup array)的键,来引用它的模型对象。

一个例子:
我们创建了一个类型为myObj的对象,它有一个可以点击的标题栏,调用函数myObj.foo()。

全局数组如下:
var MyObjects = new Array();

构造函数,在数组中注册模型对象:
function myObj(id)
{
this.uid = id;
MyObjects[this.uid] = this;
……
this.render();
}

myObj.prototype.foo = function()
{
alert(‘foooo!!!’ + this.uid);
}

render()方法,用于创建不同的DOM节点:

myObj.prototype.render = function()
{
……
this.body = document.createElement(“div”);
this.body.id = this.uid +”_body” ;
……
this.titleBar = document.createElement(“div”);
this.titleBar.id = this.uid + “_titleBar”;
this.titleBar.onclick = fooEventHandler;
……
}

可以读一下代码,可以发现当在这个模型对象的视图中构建任何DOM节点时,我们为它们分配了一个包含了模型对象ID的ID值。

我们继续完成代码,上面我们引用了函数fooEventHandler(),并且将它设置为标题栏DOM元素的onclick属性:
function fooEventHandler(event)
{
var modelObj = getMyObj(this.id);
if(modelObj)
{
modelObj.foo();
}
}

继续:
function getMyObj(id)
{
var key = id.split(“_”)[0];
return MyObjects[key];
}

事件处理函数有一个到DOM节点的引用(即this),可以从它的id属性中抽取出一个键,用来从全局数组获得模型对象。


到这里这个例子就结束了,记住这个方法叫做名称引用模型(Reference Model By Name)的方法。那开始下一个更加简单,更加清晰的方法,这种方法不会给你的DOM树加上很多冗长的ID。

向DOM节点附加模型

所有工作都使用对象引用来完成,而不是使用字符串,也不需要全局查找数组。这种方法相当大地简化了事件处理函数的工作。模型对象的构造函数不再需要专门的ID处理,foo()方法和前面定义的一样。当构造DOM节点时,我们发掘了JavaScript可以附加任意属性到任何对象上的动态能力,并且将模型对象直接附加在接收事件的DOM节点上面:

myObj.prototype.createView =function()
{
……
this.body = document.createElement(“div”);
this.body.modelObj = this;
……
this.titleBar = document.createElement(“div”);
this.titleBar.modelObj = this;
this.titleBar.onclick = fooEventHandler;
……
}

当编写事件处理函数的时候,我们可以获得一个到后端模型的直接引用:
function fooEventHandler(event)
{
var modelObj = this.modelObj;
if(modelObj)
{
modelObj.foo();
}
}

没有发现函数,也没有全局查找表,它是非常简单的。
警告:当使用这种模式的时候,我们在DOM变量和非DOM变量之间创建了循环引用。


总结:函数在上下文之间切换的能力可能在最初会把人搞糊涂,但是理解其背后的模型可以帮助我们更好地使用它。那么今天就到这里,下一站:语言创建闭包的能力~~~~~~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值