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的另類力量。^^