国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

<<編寫可維護(hù)的javascript>> 筆記7(事件處理)

microelec / 3482人閱讀

摘要:在所有應(yīng)用中事件處理都是非常重要的所有的均通過(guò)事件綁定到上所以大多數(shù)前端工程師需要花費(fèi)很多時(shí)間來(lái)編寫和修改事件處理程序遺憾的是在誕生之初這部分內(nèi)容并未受太多重視甚至當(dāng)開(kāi)發(fā)者們開(kāi)始熱衷于將傳統(tǒng)的軟件架構(gòu)概念融入到里時(shí)事件綁定仍然沒(méi)有收到多大重

在所有JavaScript應(yīng)用中事件處理都是非常重要的. 所有的JavaScript均通過(guò)事件綁定到UI上, 所以大多數(shù)前端工程師需要花費(fèi)很多時(shí)間來(lái)編寫和修改事件處理程序. 遺憾的是, 在JavaScript誕生之初, 這部分內(nèi)容并未受太多重視. 甚至當(dāng)開(kāi)發(fā)者們開(kāi)始熱衷于將傳統(tǒng)的軟件架構(gòu)概念融入到JavaScript里時(shí), 事件綁定仍然沒(méi)有收到多大重視. 大多數(shù)事件處理相關(guān)的代碼和時(shí)間環(huán)境(對(duì)于開(kāi)發(fā)者來(lái)說(shuō), 每次時(shí)間出發(fā)時(shí)才可能會(huì)用)緊緊耦合在一起, 導(dǎo)致可維護(hù)性很糟糕.

7.1 典型用法
多數(shù)開(kāi)發(fā)者都很了解, 當(dāng)事件出發(fā)時(shí), 事件對(duì)象(event 對(duì)象) 會(huì)作為回調(diào)參數(shù)傳入事件處理程序中. event對(duì)象包含所有和事件相關(guān)的信息, 包括事件的宿主(target) 以及其他和事件類型相關(guān)的數(shù)據(jù). 鼠標(biāo)事件會(huì)將其位置信息暴露在event對(duì)象上, 鍵盤事件會(huì)將按鍵信息暴露在event對(duì)象上, 觸屏事件會(huì)將觸摸位置和持續(xù)事件(duration) 暴露在event對(duì)象上, 只有提供了所有這些信息, UI才會(huì)正確地執(zhí)行交互.

在很多場(chǎng)景中, 你只是用到了event所提供信息的一小部分, 看下面這段代碼.

// 不好的寫法
function handleClick(event) {
    var popup = document.getElementById("popup");
    popup.style.left = event.clientX + "px";
    popup.style.top = event.clientY + "px";
    popup.className = "reveal";
}

addListener(element, "click", handleClick);

這段代碼只用到了event對(duì)象的兩個(gè)屬性: clientX和 clientY. 在將元素顯示在頁(yè)面里之前先用這兩個(gè)屬性給它作定位. 盡管這段代碼看起來(lái)非常簡(jiǎn)單且沒(méi)有什么問(wèn)題, 但實(shí)際上是不好的寫法, 因?yàn)檫@種做法有其局限性.

7.2 規(guī)則1: 隔離應(yīng)用邏輯
上段實(shí)例代碼的第一個(gè)問(wèn)題是事件處理程序包含了應(yīng)用邏輯(application logic). 應(yīng)用邏輯是和應(yīng)用相關(guān)的功能性代碼, 而不是和用戶行為相關(guān)的. 上段實(shí)例代碼中, 應(yīng)用邏輯實(shí)在特定位置顯示一個(gè)彈出框. 盡管這個(gè)交互應(yīng)當(dāng)是在用戶點(diǎn)擊某個(gè)元素時(shí)發(fā)生的, 但情況并不總是如此.

將應(yīng)用邏輯從所有時(shí)間處理程序中抽離出來(lái)的做法是一種最佳實(shí)踐, 應(yīng)為說(shuō)不定什么事件其他地方就會(huì)觸發(fā)同一段邏輯. 比如, 有時(shí)你需要在用戶將鼠標(biāo)移到某個(gè)元素上時(shí)判斷是否顯示彈出框, 或者當(dāng)按下鍵盤上的某個(gè)鍵時(shí)也作同樣的邏輯判斷. 這樣多個(gè)時(shí)間的處理程序執(zhí)行的同樣的邏輯, 而你的代碼卻被不小心賦值了多份.

將應(yīng)用邏輯放置于事件處理程序中的另一個(gè)確定是和測(cè)試有關(guān)的. 測(cè)試時(shí)需要直接出發(fā)功能代碼, 而不必通過(guò)模擬對(duì)元素點(diǎn)擊來(lái)出發(fā). 如果將應(yīng)用邏輯放置于事件處理程序中, 唯一的測(cè)試方法是制造事件的觸發(fā). 盡管某些測(cè)試框架可以模擬觸發(fā)事件, 但實(shí)際上這不是測(cè)試的最佳方法. 調(diào)用功能性代碼最好的做法就是單個(gè)函數(shù)調(diào)用.

你總是需要將應(yīng)用邏輯和事件處理的代碼拆分開(kāi)來(lái). 如果要對(duì)上一段實(shí)例代碼進(jìn)行重構(gòu), 第一步是將處理彈出邏輯框的代碼放入一個(gè)多帶帶的函數(shù)中, 這個(gè)函數(shù)很可能掛在與為該應(yīng)用定義的一個(gè)全局對(duì)象上. 事件處理程序應(yīng)當(dāng)總是在一個(gè)相同的全局對(duì)象中, 因此就有了以下兩個(gè)辦法:

// 好的寫法 - 拆分應(yīng)用邏輯
var MyApplication = {
    handleClick: function(event) {
        this.showPopup(event);
    }
    
    showPopup: function(event) {
        var popup = document.getElementById("popup");
        popup.style.left = event.clientX + "px";
        popup.style.top = event.clientY + "px";
        popup.className = "reveal";
    }
};

addListener(element, "click", function(evnet) {
    MyApplication.handleClick(event);
})

之前在事件處理程序中包含了所有應(yīng)用邏輯現(xiàn)在轉(zhuǎn)移到了MyApplication.showPopup()方法中. 現(xiàn)在MyApplication.handleClick()方法制作一件事情, 即調(diào)用MyApplication.showPopup(). 若應(yīng)用邏輯被剝離出去, 對(duì)同一段功能代碼的調(diào)用可以在多點(diǎn)發(fā)生, 則不需要一定依賴于某個(gè)特定時(shí)間的觸發(fā), 這顯然更加方便. 單著只是拆解時(shí)間處理程序代碼的第一步.

7.3 規(guī)則2: 不要分發(fā)事件對(duì)象
在剝離出應(yīng)用邏輯之后, 上段實(shí)例代碼和存在一個(gè)問(wèn)題, 即event對(duì)象被無(wú)節(jié)制地分發(fā). 它從匿名的時(shí)間處理函數(shù)傳入了MyApplication.handleClick(), 然后又傳入了MyApplication.showPopup(). 正如上文提到的, event對(duì)象上包含很多和事件相關(guān)的額外信息, 而這段代碼只用到了其中的兩個(gè)而已.

應(yīng)用邏輯不應(yīng)當(dāng)依賴于event對(duì)象來(lái)正確完成功能, 原因如下.

方法接口并沒(méi)有表明哪些數(shù)據(jù)是必要的. 好的API一定是對(duì)于期望和依賴都是透明的. 將event對(duì)象作為參數(shù)并不能告訴你event的哪些屬性時(shí)有用的, 用來(lái)干什么?

因此, 如果你想測(cè)試這個(gè)方法, 你必須重新創(chuàng)建一個(gè)event對(duì)象并將它作為參數(shù)傳入. 所以, 你需要確切的知道張哥方法使用了哪些信息, 這樣才能正切地寫出測(cè)試代碼.

這些問(wèn)題在大型Web應(yīng)用中都是不可取的. 代碼不夠明晰就會(huì)導(dǎo)致bug.

最佳的辦法是讓事件處理程序使用event對(duì)象來(lái)處理事件, 然后拿到所有需要的數(shù)據(jù)傳給應(yīng)用邏輯. 例如, MyApplication.showPopup()方法只需要兩個(gè)數(shù)據(jù), x坐標(biāo)和y坐標(biāo). 這樣我們將方法重寫一下, 讓它來(lái)接受這兩個(gè)參數(shù).

// 好的寫法
var MyApplication = {
    handleClick: function(event) {
        this.showPopup(event.clientX, event.clientY);
    }
    
    showPopup: function(x, y) {
        var popup = document.getElementById("popup");
        popup.style.left = x + "px";
        popup.style.top = y + "px";
        popup.className = "reveal";
    }
};

addListener(element, "click", function(evnet) {
    MyApplication.handleClick(event);
})

在這段重寫大代碼中, MyApplication.handleClick()將x坐標(biāo)和y坐標(biāo)傳入了MyApplication .showPopup(), 代替了之前傳入的事件對(duì)象. 可以很清晰的看到MyApplication.showPopup()所期望傳入的參數(shù), 并且在測(cè)試或代碼的任意位置都可以很輕易的直接調(diào)用這段邏輯, 比如:

MyApplication.showPopup(10, 10);

當(dāng)處理事件時(shí), 最好讓事件處理程序成為接觸到event對(duì)象的唯一的函數(shù). 事件處理程序應(yīng)當(dāng)在進(jìn)入應(yīng)用邏輯之前針對(duì)event對(duì)象執(zhí)行任何必要的操作, 包括阻止默認(rèn)事件或阻止冒泡, 都應(yīng)當(dāng)直接包含在事件處理程序中, 比如:

// 好的做法
var MyApplication = {
    handleClick: function(event) {
    
        // 假設(shè)事件支持DOM Level2
        event.preventDefault();
        event.stopPropagation();
        
        // 傳入應(yīng)用邏輯
        this.showPopup(event.clientX, event.clientY);
    }
    
    showPopup: function(x, y) {
        var popup = document.getElementById("popup");
        popup.style.left = x + "px";
        popup.style.top = y + "px";
        popup.className = "reveal";
    }
};

addListener(element, "click", function(evnet) {
    MyApplication.handleClick(event);
})

在這段代碼中, MyApplication.handleClick()是事件處理程序, 因此它是在將數(shù)據(jù)傳入應(yīng)用邏輯之前調(diào)用了event.preventDefault()和event.stopPropagation(), 這清楚的展示了事件處理程序和應(yīng)用邏輯之間的分工. 因?yàn)閼?yīng)用邏輯不需要對(duì)event產(chǎn)生依賴, 進(jìn)而在很多地方都可以輕松的使用相同的業(yè)務(wù)邏輯, 包括寫測(cè)試代碼.

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/89212.html

相關(guān)文章

  • &lt;&lt;編寫維護(hù)javascript&gt;&gt; 筆記9(將配置數(shù)據(jù)從代碼中分離出來(lái)

    摘要:代碼無(wú)非是定義一些指令的集合讓計(jì)算機(jī)來(lái)執(zhí)行我們常常將數(shù)據(jù)傳入計(jì)算機(jī)由指令對(duì)數(shù)據(jù)進(jìn)行操作并最終產(chǎn)生一個(gè)結(jié)果當(dāng)不得不修改數(shù)據(jù)時(shí)問(wèn)題就來(lái)了任何時(shí)候你修改源代碼都會(huì)有引入的風(fēng)險(xiǎn)且值修改一些數(shù)據(jù)的值也會(huì)帶來(lái)一些不必要的風(fēng)險(xiǎn)因?yàn)閿?shù)據(jù)時(shí)不應(yīng)當(dāng)影響指令的正 代碼無(wú)非是定義一些指令的集合讓計(jì)算機(jī)來(lái)執(zhí)行. 我們常常將數(shù)據(jù)傳入計(jì)算機(jī), 由指令對(duì)數(shù)據(jù)進(jìn)行操作, 并最終產(chǎn)生一個(gè)結(jié)果. 當(dāng)不得不修改數(shù)據(jù)時(shí)問(wèn)題就來(lái)...

    xbynet 評(píng)論0 收藏0
  • &lt;&lt;編寫維護(hù)javascript&gt;&gt; 筆記3(語(yǔ)句和表達(dá)式)

    摘要:所有的塊語(yǔ)句都應(yīng)當(dāng)使用花括號(hào)包括花括號(hào)的對(duì)齊方式第一種風(fēng)格第二種風(fēng)格塊語(yǔ)句間隔第一種在語(yǔ)句名圓括號(hào)和左花括號(hào)之間沒(méi)有空格間隔第二種在左圓括號(hào)之前和右圓括號(hào)之后各添加一個(gè)空格第三種在左圓括號(hào)后和右圓括號(hào)前各添加一個(gè)空格我個(gè)人喜歡在右括號(hào)之后添 所有的塊語(yǔ)句都應(yīng)當(dāng)使用花括號(hào), 包括: if for while do...while... try...catch...finally 3....

    OBKoro1 評(píng)論0 收藏0
  • &lt;&lt;編寫維護(hù)javascript&gt;&gt; 筆記5(UI層松耦合)

    摘要:由于第四章太稀松平常了于是就直接跳到第五章了這里我就草草的說(shuō)一下第四章的幾個(gè)點(diǎn)吧在嚴(yán)格模式的應(yīng)用下不推薦將用在全局作用域中相等推薦盡量使用和守則如果是在沒(méi)有別的方法來(lái)完成當(dāng)前任務(wù)這時(shí)可以使用原始包裝類型不推薦創(chuàng)建類型時(shí)用等創(chuàng)建類型從這一章節(jié) 由于第四章太稀松平常了, 于是就直接跳到第五章了.這里我就草草的說(shuō)一下第四章的幾個(gè)點(diǎn)吧 在嚴(yán)格模式的應(yīng)用下 不推薦將use strict;用在全...

    saucxs 評(píng)論0 收藏0
  • &lt;&lt;編寫維護(hù)javascript&gt;&gt; 筆記2(注釋)

    摘要:注釋是代碼中最常見(jiàn)的組成部分它們是另一種形式的文檔也是程序員最后才舍得花時(shí)間去寫的但是對(duì)于代碼的總體可維護(hù)性而言注釋是非常重要的一環(huán)打開(kāi)一個(gè)沒(méi)有任何注釋的文件就好像趣味冒險(xiǎn)但如果給你的時(shí)間有限這項(xiàng)任務(wù)就變成了折磨適度的添加注釋可以解釋說(shuō)明代 注釋是代碼中最常見(jiàn)的組成部分.它們是另一種形式的文檔,也是程序員最后才舍得花時(shí)間去寫的.但是,對(duì)于代碼的總體可維護(hù)性而言,注釋是非常重要的一環(huán).打...

    renweihub 評(píng)論0 收藏0
  • &lt;&lt;編寫維護(hù)javascript&gt;&gt; 筆記1(基本格式化)

    摘要:程序是寫給人讀的只是偶爾讓計(jì)算機(jī)執(zhí)行一下當(dāng)你剛剛組建一個(gè)團(tuán)隊(duì)時(shí)團(tuán)隊(duì)中的每個(gè)人都各自有一套編程習(xí)慣畢竟每個(gè)成員都有著不同的背景有些人可能來(lái)自某個(gè)皮包公司身兼數(shù)職在公司里面什么事都做還有些人會(huì)來(lái)自不同的團(tuán)隊(duì)對(duì)某種特定的做事風(fēng)格情有獨(dú)鐘或恨之入骨 程序是寫給人讀的,只是偶爾讓計(jì)算機(jī)執(zhí)行一下. Donald Knuth 當(dāng)你剛剛組建一個(gè)團(tuán)隊(duì)時(shí),團(tuán)隊(duì)中的每個(gè)人都各自有一套編程習(xí)慣.畢竟,...

    wfc_666 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<