javascript事件驅動模型的不完全剖析

來源:互聯網
上載者:User
javascript 由於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的另類力量。^^

相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。