淺談JavaScript之事件綁定
更新時(shí)間:2013年07月08日 09:52:18 作者:
關(guān)于 JavaScript 的事件綁定在網(wǎng)上已經(jīng)有不少相關(guān)的資料了,今天這篇文章也是在被同事問(wèn)及的時(shí)候才順便把它記錄下來(lái),算是 JavaScript 事件綁定中的一個(gè)小技巧,如果能在工作中善加利用,會(huì)有出其不意的效果
其實(shí)沒(méi)有什么新的知識(shí)點(diǎn),只是為了方便其他有需要的朋友們翻閱,對(duì)自己而言也算是一個(gè)積累,所以只能算是閑談 JavaScript,老鳥(niǎo)們可以盡情飄過(guò)。
在進(jìn)入正題之前,先提個(gè)問(wèn)題熱熱身吧。
現(xiàn)在有如下 HTML 結(jié)構(gòu):
<div id="wrap">
<input type="button" value="按鈕一" />
<input type="button" value="按鈕二" />
<input type="button" value="按鈕三" />
<input type="button" value="按鈕四" />
<input type="button" value="按鈕五" />
</div>
以及如下 JavaScript 代碼:
var wrap = document.getElementById('wrap'),
inputs = wrap.getElementsByTagName('input');
for (var i = 0, l = inputs.length; i < l; i++) {
inputs[i].onclick = function () {
alert(i);
}
}
請(qǐng)問(wèn),這樣執(zhí)行的結(jié)果是什么?
/***************************分割線***************************/
如果你的回答是“點(diǎn)擊按鈕時(shí), alert 當(dāng)前按鈕的索引值 i”,那你就中了我的圈套了。大家不妨試試,無(wú)論你點(diǎn)擊哪個(gè)按鈕,它都會(huì)alert(5)。
這個(gè)看似理所當(dāng)然的結(jié)果為什么會(huì)和實(shí)際情況不同呢?其實(shí)也是很好理解的。
因?yàn)?onclick 只是事件綁定,而不是執(zhí)行,當(dāng)我們執(zhí)行 onclick 事件的時(shí)候,這時(shí)的 i 已經(jīng)是循環(huán)以后的值了,照這樣看,每個(gè)按鈕都alert(5) 也就不足為奇了。
那么,如果我們要怎么實(shí)現(xiàn)“點(diǎn)擊按鈕時(shí),alert 當(dāng)前按鈕的索引值 i”呢?這里就要用到 JavaScript 中暗藏玄機(jī)的一個(gè)概念“閉包”。我們可以用閉包的方式改寫(xiě)以上 JS,把 for 循環(huán)中的 i 值保存在內(nèi)存中,代碼如下:
var wrap = document.getElementById('wrap'),
inputs = wrap.getElementsByTagName('input');
for (var i = 0, l = inputs.length; i < l; i++) {
(function (cur) {
inputs[cur].onclick = function () {
alert(cur);
}
})(i)
}
再試試效果?確實(shí)能 alert 出相應(yīng)的索引值了,不過(guò)至此為止還只是開(kāi)胃菜,正題才剛剛開(kāi)始!
以上的方法,我們是通過(guò)循環(huán) + 閉包給 button 按鈕上綁定事件,我們知道,在 JavaScript 中函數(shù)也是對(duì)象,對(duì)象就會(huì)占用內(nèi)存,現(xiàn)在的例子中只有 5 個(gè)按鈕,或許你會(huì)認(rèn)為這樣的性能開(kāi)銷可以忽略不計(jì),但是如果當(dāng)我們有 50個(gè),甚至 500 個(gè)按鈕的時(shí)候,IE 已經(jīng)哭了,當(dāng)有更多其他性能隱患并發(fā)時(shí),所有的瀏覽器都哭了。
回到剛才的例子,我們可以用“事件委托”的方法來(lái)解決這個(gè)因綁定事件隨著按鈕增加而可能導(dǎo)致的性能問(wèn)題。原理很簡(jiǎn)單,利用 Javascript 的事件冒泡,我們可以把事件的綁定從按鈕移到它們的父級(jí)元素上,不管按鈕有多少,它們只有一個(gè)共同的父級(jí)元素,那樣我們只需要綁定一次事件就可以了。
代碼如下:
var wrap = document.getElementById('wrap'),
inputs = wrap.getElementsByTagName('input');
wrap.onclick = function (ev) {
var ev = ev || window.event,
target = ev.target || ev.srcElement;
for (var i = 0, l = inputs.length; i < l; i++) {
if (inputs[i] === target) {
alert(i)
}
}
}
至此,正餐完畢,我們還可以再深入一下,來(lái)些餐后甜點(diǎn)。
除了在性能上,事件委托比閉包的事件綁定更有優(yōu)勢(shì)以外,事件委托還無(wú)需顧及子元素(即被綁定事件的元素)的數(shù)量。比如,我們?cè)?onclick 事件綁定以后,增加一個(gè)按鈕:
var newInput = document.createElement('input');
newInput.setAttribute('type', 'button');
newInput.setAttribute('value', '按鈕六');
wrap.appendChild(newInput);
同樣在最后加了這段代碼的閉包方式和事件委托方式,我們可以看到,閉包實(shí)現(xiàn)的事件綁定中點(diǎn)擊“按鈕六”毫無(wú)效果,但是在事件委托中實(shí)現(xiàn)的事件綁定點(diǎn)擊“按鈕六”則會(huì)有 alert。相反,如果我們要?jiǎng)h除一個(gè)按鈕,閉包的方式仍會(huì)在內(nèi)存中保存已刪除按鈕的 onclick 事件(除非手動(dòng)設(shè)為 null),事件委托則不會(huì)對(duì)內(nèi)存造成多余的負(fù)擔(dān),就為這個(gè)原因,我們也應(yīng)該多加利用事件委托的方式來(lái)綁定同一層級(jí)的多個(gè)元素。
在進(jìn)入正題之前,先提個(gè)問(wèn)題熱熱身吧。
現(xiàn)在有如下 HTML 結(jié)構(gòu):
復(fù)制代碼 代碼如下:
<div id="wrap">
<input type="button" value="按鈕一" />
<input type="button" value="按鈕二" />
<input type="button" value="按鈕三" />
<input type="button" value="按鈕四" />
<input type="button" value="按鈕五" />
</div>
以及如下 JavaScript 代碼:
復(fù)制代碼 代碼如下:
var wrap = document.getElementById('wrap'),
inputs = wrap.getElementsByTagName('input');
for (var i = 0, l = inputs.length; i < l; i++) {
inputs[i].onclick = function () {
alert(i);
}
}
請(qǐng)問(wèn),這樣執(zhí)行的結(jié)果是什么?
/***************************分割線***************************/
如果你的回答是“點(diǎn)擊按鈕時(shí), alert 當(dāng)前按鈕的索引值 i”,那你就中了我的圈套了。大家不妨試試,無(wú)論你點(diǎn)擊哪個(gè)按鈕,它都會(huì)alert(5)。
這個(gè)看似理所當(dāng)然的結(jié)果為什么會(huì)和實(shí)際情況不同呢?其實(shí)也是很好理解的。
因?yàn)?onclick 只是事件綁定,而不是執(zhí)行,當(dāng)我們執(zhí)行 onclick 事件的時(shí)候,這時(shí)的 i 已經(jīng)是循環(huán)以后的值了,照這樣看,每個(gè)按鈕都alert(5) 也就不足為奇了。
那么,如果我們要怎么實(shí)現(xiàn)“點(diǎn)擊按鈕時(shí),alert 當(dāng)前按鈕的索引值 i”呢?這里就要用到 JavaScript 中暗藏玄機(jī)的一個(gè)概念“閉包”。我們可以用閉包的方式改寫(xiě)以上 JS,把 for 循環(huán)中的 i 值保存在內(nèi)存中,代碼如下:
復(fù)制代碼 代碼如下:
var wrap = document.getElementById('wrap'),
inputs = wrap.getElementsByTagName('input');
for (var i = 0, l = inputs.length; i < l; i++) {
(function (cur) {
inputs[cur].onclick = function () {
alert(cur);
}
})(i)
}
再試試效果?確實(shí)能 alert 出相應(yīng)的索引值了,不過(guò)至此為止還只是開(kāi)胃菜,正題才剛剛開(kāi)始!
以上的方法,我們是通過(guò)循環(huán) + 閉包給 button 按鈕上綁定事件,我們知道,在 JavaScript 中函數(shù)也是對(duì)象,對(duì)象就會(huì)占用內(nèi)存,現(xiàn)在的例子中只有 5 個(gè)按鈕,或許你會(huì)認(rèn)為這樣的性能開(kāi)銷可以忽略不計(jì),但是如果當(dāng)我們有 50個(gè),甚至 500 個(gè)按鈕的時(shí)候,IE 已經(jīng)哭了,當(dāng)有更多其他性能隱患并發(fā)時(shí),所有的瀏覽器都哭了。
回到剛才的例子,我們可以用“事件委托”的方法來(lái)解決這個(gè)因綁定事件隨著按鈕增加而可能導(dǎo)致的性能問(wèn)題。原理很簡(jiǎn)單,利用 Javascript 的事件冒泡,我們可以把事件的綁定從按鈕移到它們的父級(jí)元素上,不管按鈕有多少,它們只有一個(gè)共同的父級(jí)元素,那樣我們只需要綁定一次事件就可以了。
代碼如下:
復(fù)制代碼 代碼如下:
var wrap = document.getElementById('wrap'),
inputs = wrap.getElementsByTagName('input');
wrap.onclick = function (ev) {
var ev = ev || window.event,
target = ev.target || ev.srcElement;
for (var i = 0, l = inputs.length; i < l; i++) {
if (inputs[i] === target) {
alert(i)
}
}
}
至此,正餐完畢,我們還可以再深入一下,來(lái)些餐后甜點(diǎn)。
除了在性能上,事件委托比閉包的事件綁定更有優(yōu)勢(shì)以外,事件委托還無(wú)需顧及子元素(即被綁定事件的元素)的數(shù)量。比如,我們?cè)?onclick 事件綁定以后,增加一個(gè)按鈕:
復(fù)制代碼 代碼如下:
var newInput = document.createElement('input');
newInput.setAttribute('type', 'button');
newInput.setAttribute('value', '按鈕六');
wrap.appendChild(newInput);
同樣在最后加了這段代碼的閉包方式和事件委托方式,我們可以看到,閉包實(shí)現(xiàn)的事件綁定中點(diǎn)擊“按鈕六”毫無(wú)效果,但是在事件委托中實(shí)現(xiàn)的事件綁定點(diǎn)擊“按鈕六”則會(huì)有 alert。相反,如果我們要?jiǎng)h除一個(gè)按鈕,閉包的方式仍會(huì)在內(nèi)存中保存已刪除按鈕的 onclick 事件(除非手動(dòng)設(shè)為 null),事件委托則不會(huì)對(duì)內(nèi)存造成多余的負(fù)擔(dān),就為這個(gè)原因,我們也應(yīng)該多加利用事件委托的方式來(lái)綁定同一層級(jí)的多個(gè)元素。
您可能感興趣的文章:
- JS 事件綁定、事件監(jiān)聽(tīng)、事件委托詳細(xì)介紹
- Javascript 事件流和事件綁定
- javaScript 事件綁定、事件冒泡、事件捕獲和事件執(zhí)行順序整理總結(jié)
- JS 事件綁定函數(shù)代碼
- javascript實(shí)現(xiàn)簡(jiǎn)單的on事件綁定
- js事件綁定快捷鍵以ctrl+k為例
- 關(guān)于JavaScript中事件綁定的方法總結(jié)
- javascript 處理事件綁定的一些兼容寫(xiě)法
- JS的事件綁定深入認(rèn)識(shí)
- Javascript函數(shù)加殼多用于事件綁定
- JS事件綁定的常用方式實(shí)例總結(jié)
相關(guān)文章
window.showModalDialog()返回值的學(xué)習(xí)心得總結(jié)
本篇文章主要介紹了window.showModalDialog()返回值的學(xué)習(xí)心得。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2014-01-01淺談addEventListener和attachEvent的區(qū)別
下面小編就為大家?guī)?lái)一篇淺談addEventListener和attachEvent的區(qū)別。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-07-07微信小程序簡(jiǎn)單實(shí)現(xiàn)form表單獲取輸入數(shù)據(jù)功能示例
這篇文章主要介紹了微信小程序簡(jiǎn)單實(shí)現(xiàn)form表單獲取輸入數(shù)據(jù)功能,涉及微信小程序針對(duì)form表單的事件綁定及數(shù)據(jù)獲取等相關(guān)操作技巧,需要的朋友可以參考下2017-11-116種JavaScript繼承方式及優(yōu)缺點(diǎn)(小結(jié))
這篇文章主要介紹了6種JavaScript繼承方式及優(yōu)缺點(diǎn)(小結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02