• 软件测试技术
  • 软件测试博客
  • 软件测试视频
  • 开源软件测试技术
  • 软件测试论坛
  • 软件测试沙龙
  • 软件测试资料下载
  • 软件测试杂志
  • 软件测试人才招聘
    暂时没有公告

字号: | 推荐给好友 上一篇 | 下一篇

javascript事件驱动模型的不完全剖析

发布: 2007-5-25 23:40 | 作者: 佚名 | 来源: 互连网 | 查看: 21次 | 进入软件测试论坛讨论

领测软件测试网 由于javascript并不是真正意义上“面向对象”的语言,所以,在实现事件驱动模型的时候,总是会遇到一些困难。
当然这里指的事件驱动并不是指javascript固有的事件处理机制或者DOM的事件模型,而是指类似C#或者Java的那种事件模型。

javascript在处理事件驱动的时候最大的问题在于"this指针"困惑。
例如:<input type="button" onclick=function(){alert(this.value);} value="Hello World!"/>
这里的this指针毫无疑问是没有问题的
但是,<input type="button" id="button1"/>
var objBtn = document.getElementById("button1");
objBtn.attachEvent('onclick', EventHandler);
function EventHandler()
{
      alert(this.value);
}
运行这个脚本很吃惊地发现得到的是完全错误的结果
因为这里的this并不是objBtn这个input对象!而是全局的window对象!
类似的问题在javascript中还会经常出现

再比如一个更复杂的应用:
function mainForm(form)
{
    this.form = form;
    this.button1 = form.buttonOK;
    this.button2 = form.buttonCancel;
    this.button1.onclick = Button1_Click;  //为按钮注册单击事件
    this.button2.onclick = Button2_Click;
    mainForm.prototype. Button1_Click = function()
    {
       alert(this.button1.value);
    }
    mainForm.prototype.Button2_Click = function()
    {
        this.form.style.display = 'none';
    }
}

本来一段挺“漂亮”的代码,却不能正确运行,为什么呢?原来问题还是在this上,button1_Clicked和button2_Clicked两个函数虽然是mainForm类的成员函数,但是他们是被this.button1.onclick和this.button2.onclick调用(不完全准确的说法)的,所以函数中的this指得是button1和button2两个对象!这很令人困扰,不是吗?

为了解决这个问题,必须要保证函数调用者是mainForm对象而不是button或者其他的什么成员,为此,我思考出一种事件注册的机制,将上面的代码写成:
this.button1.ClickEventSender = this;
this.button1.onclick = function(){this.ClickEventSender.Button1_Click(this.ClickEventSender,self.event);}
mainForm.prototype.Button1_Click = function(object, sender)
{
      alert(this.button1.value);
}
就得到了正确结果。

于是,一种完全的基于“后台代码”的“事件驱动”模型慢慢成型,下面是一段简短的Demo代码:

//后台代码
//事件驱动框架(演示)
//2004-11-16 Created
//2004-11-17 Modified
//ControlDemo.js
function ControlDemo(page)
{
        //初始化Page
        if (page == null)
        {
                page = self;
        }
        if (page != self)
        {
                //Do sth. here...
        }
        this.page = page;

        //Properties
        this.keyPressed = 0;

        //Controlable Entities       
        //PageBody 注册PageLoad事件
        this.body1 = page.document.getElementById("main");
        this.page.PageLoadEventSender = this;
        this.body1.onload = function(){this.PageLoadEventSender.PageLoad(this.PageLoadEventSender,page.event);}
       
        //Button1 注册Click事件
        this.button1 = page.button1;
        this.button1.value = "确定";
        this.button1.ClickEventSender = this;
        this.button1.onclick = function(){this.ClickEventSender.Button1_Click(this.ClickEventSender,page.event);}

        //Button2 注册Click事件
        this.button2 = page.button2;
        this.button2.value = "取消";
        this.button2.ClickEventSender = this;
        this.button2.onclick = function(){this.ClickEventSender.Button2_Click(this.ClickEventSender,page.event);}
       
        //Textbox1 注册KeyUp、MouseMove事件
        this.textbox1 = page.textbox1;
        this.textbox1.style.width = "100%";
        this.textbox1.rows = 10;
        this.textbox1.KeyUpSender = this;
        this.textbox1.onkeyup = function(){this.KeyUpSender.Textbox1_KeyUp(this.KeyUpSender,page.event);}
        this.textbox1.MouseMoveSender = this;
        this.textbox1.onmousemove = function(){this.MouseMoveSender.Textbox1_MouseMove(this.MouseMoveSender, page.event);}

        //Labels
        this.label1 = page.document.getElementById("label1");
        this.label2 = page.document.getElementById("label2");
        this.label3 = page.document.getElementById("label3");

        //EventHandlers 事件处理函数
        ControlDemo.prototype.PageLoad = function(sender,event)
        {
                this.page.defaultStatus = "事件驱动框架演示~~";
                this.page.resizeTo(600,400);
        }
        ControlDemo.prototype.Button1_Click = function(sender,event)
        {
                alert("Hello ^_^");
        }
        ControlDemo.prototype.Button2_Click = function(sender,event)
        {
                if (page.opener == null)
                {
                        page.opener = page;
                }
                page.close();
        }
        ControlDemo.prototype.Textbox1_KeyUp = function(sender, event)
        {
                this.keyPressed++;
                this.label1.innerText = this.keyPressed;
                this.label2.innerText = this.textbox1.value.length;
                this.label3.innerText = event.keyCode;
        }
        ControlDemo.prototype.Textbox1_MouseMove = function(sender, event)
        {
                this.page.status = "鼠标位置:x="+event.x+"    y="+event.y;
        }
}


<!--前台页面-->
<html>
<head>
<title>事件驱动框架演示</title>
</head>
<body id = "main">
<div align="center" id="div1">
        <textarea name="textbox1" id="textbox1"></textarea><br/>
        键盘点击次数为<span id="label1">0</span>次,共键入<span id="label2">0</span>个字符,最后输入的字符码为
        <span id="label3">0</span>
        <br/>
        <input type="button" name="button1" id="button1"></input>
        <input type="button" name="button2" id="button2"></input>
</div>
</body>
</html>
<script language="javascript" type="text/javascript" src="ControlDemo.js"></script>
<script language="javascript" type="text/javascript">
var demo = new ControlDemo();
</script>

是不是感觉页面上的代码很简洁?
几乎只是放置对象和构造类,其他什么也不做。
而编写后台代码是不是让用asp.net的朋友有一种“似曾相识”的感觉?
虽然不敢说一定好,但,这就是javascript的另类力量。^^

延伸阅读

文章来源于领测软件测试网 https://www.ltesting.net/


关于领测软件测试网 | 领测软件测试网合作伙伴 | 广告服务 | 投稿指南 | 联系我们 | 网站地图 | 友情链接
版权所有(C) 2003-2010 TestAge(领测软件测试网)|领测国际科技(北京)有限公司|软件测试工程师培训网 All Rights Reserved
北京市海淀区中关村南大街9号北京理工科技大厦1402室 京ICP备10010545号-5
技术支持和业务联系:info@testage.com.cn 电话:010-51297073

软件测试 | 领测国际ISTQBISTQB官网TMMiTMMi认证国际软件测试工程师认证领测软件测试网