淺談JavaScript之事件綁定

來源:互聯網
上載者:User

其實沒有什麼新的知識點,只是為了方便其他有需要的朋友們翻閱,對自己而言也算是一個積累,所以只能算是閑談 JavaScript,老鳥們可以盡情飄過。
在進入正題之前,先提個問題熱熱身吧。
現在有如下 HTML 結構:
複製代碼 代碼如下:
<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);
    }
}

請問,這樣執行的結果是什嗎?
/***************************分割線***************************/
如果你的回答是“點擊按鈕時, alert 當前按鈕的索引值 i”,那你就中了我的圈套了。大家不妨試試,無論你點擊哪個按鈕,它都會alert(5)。

這個看似理所當然的結果為什麼會和實際情況不同呢?其實也是很好理解的。
因為 onclick 只是事件綁定,而不是執行,當我們執行 onclick 事件的時候,這時的 i 已經是迴圈以後的值了,照這樣看,每個按鈕都alert(5) 也就不足為奇了。

那麼,如果我們要怎麼實現“點擊按鈕時,alert 當前按鈕的索引值 i”呢?這裡就要用到 JavaScript 中暗藏玄機的一個概念“閉包”。我們可以用閉包的方式改寫以上 JS,把 for 迴圈中的 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)
}

再試試效果?確實能 alert 出相應的索引值了,不過至此為止還只是開胃菜,正題才剛剛開始!
以上的方法,我們是通過迴圈 + 閉包給 button 按鈕上綁定事件,我們知道,在 JavaScript 中函數也是對象,對象就會佔用記憶體,現在的例子中只有 5 個按鈕,或許你會認為這樣的效能開銷可以忽略不計,但是如果當我們有 50個,甚至 500 個按鈕的時候,IE 已經哭了,當有更多其他效能隱患並發時,所有的瀏覽器都哭了。

回到剛才的例子,我們可以用“事件委託”的方法來解決這個因綁定事件隨著按鈕增加而可能導致的效能問題。原理很簡單,利用 Javascript 的事件冒泡,我們可以把事件的綁定從按鈕移到它們的父級元素上,不管按鈕有多少,它們只有一個共同的父級元素,那樣我們只需要綁定一次事件就可以了。
代碼如下:
複製代碼 代碼如下:
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)
        }
    }
}

至此,正餐完畢,我們還可以再深入一下,來些餐後甜點。
除了在效能上,事件委託比閉包的事件綁定更有優勢以外,事件委託還無需顧及子項目(即被綁定事件的元素)的數量。比如,我們在 onclick 事件綁定以後,增加一個按鈕:
複製代碼 代碼如下:
var newInput = document.createElement('input');
newInput.setAttribute('type', 'button');
newInput.setAttribute('value', '按鈕六');
wrap.appendChild(newInput);

同樣在最後加了這段代碼的閉包方式和事件委託方式,我們可以看到,閉包實現的事件綁定中點擊“按鈕六”毫無效果,但是在事件委託中實現的事件綁定點擊“按鈕六”則會有 alert。相反,如果我們要刪除一個按鈕,閉包的方式仍會在記憶體中儲存已刪除按鈕的 onclick 事件(除非手動設為 null),事件委託則不會對記憶體造成多餘的負擔,就為這個原因,我們也應該多加利用事件委託的方式來綁定同一層級的多個元素。

聯繫我們

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

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

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.