《JavaScript高階程式設計》事件及最佳實踐簡記
阿新 • • 發佈:2018-11-15
- 5種類型:undefined, boolean, string, number, object
- 使用typeof結果新增:null, function
- ECMAScript5中為陣列提供五種迭代方法
- every(), filter(), forEach(), map(), some()
- every和some:陣列中資料是否滿足條件,return true/false
- 使用函式的值取代函式名
- 如下錯誤
function(){ //這裡是塊級作用域 }()
- 可修改為如下:
(function(){ //這裡是塊級作用域 })(); //正確
- DOM1沒有規定事件處理
- DOM0級,繫結click方法,只能單個事件
- DOM2級,addEventListener(),可以多個事件
- 包含三個階段:事件捕獲階段、處於目標階段、事件冒泡階段
- DOM3級,包括以下及部分內容
- UI事件
- load, unload, select, resize
- 焦點事件
- focus
- 滑鼠事件
- mousedown
- mouseup
- click
- mousedown
- mouseup
- click
- dbclick
- 滾輪事件
- mousewheel
- 鍵盤事件
- keydown
- keypress
- keyup
- 文字事件
- textInput
- 複合事件
- 僅有IE9+支援
- 變動事件
- DOM中的某一部分發生變化時給出提示
- UI事件
- JavaScript最佳實踐
- 可維護性
- 可維護的程式碼
- 可理解性
- 直觀性
- 可適應性
- 可擴充套件性
- 可除錯性
- 程式碼約定
- 可讀性
- 變數和函式命名
- 變數型別透明
- 使用合適的命名方式
- 匈牙利標記法
- o:物件
- s:字串
- i:整數
- f:浮點數
- b:布林型
- 型別註釋
- 鬆散耦合
- 解耦HTML/JavaScript
- 解耦CSS/JavaScript
- 解耦應用邏輯/事件處理程式
- 程式設計實踐
- 尊正物件所有權
- 簡單的說:如果不負責建立或維護某個物件,就不能對它們進行修改
- 具體地說:
- 不要為例項或原型新增屬性
- 不要為例項或原型新增方法
- 不要重定義已存在的方法
- 避免全域性量
//兩個全域性量——避免!! var name = "Nicholas"' function sayName(){ Alert(name); } //一個全域性量——推薦 var MyApplication = { name : "Nicholas", sayName : function(){ alert(this.name); } };
- 避免與null進行比較
- 如果值應為一個引用型別,使用instanceof操作符檢查其建構函式
- 如果值應為一個基本型別,使用typeof檢查其型別
- 如果是希望物件包含某個特定的方法名,則使用typeof操作符確保指定名字的方法存在於物件上。
- 程式碼中的null比較越少,就越容易確定程式碼的目的,並消除不必要的錯誤
- 使用常量
- z定義Constants類,編寫常量key/value值
- 重複值
- 使用者介面字串
- URLs
- 任意可能會更改的值
- 尊正物件所有權
- 可維護的程式碼
- 效能
- 注意作用域
- 避免全域性查詢(涉及作用域鏈上的查詢)
- 避免with語句
- 選擇正確方法
- 避免不必要的屬性查詢(一次查詢複雜度O(n))
- 一旦多次用到物件屬性,應該將其儲存在區域性變數中
- 優化迴圈
- 減值迭代(很多情況下更高效)
- 簡化終止條件
- 簡化迴圈體
- 使用後測試迴圈(避免第一次的判斷)
- 展開迴圈
- 當迴圈次數是確定的,消除迴圈並使用多次函式呼叫往往更快
- 可以消除建立迴圈和處理終止條件的額外開銷
- 若迭代次數不能事先確定,可以考慮使用一種叫Duff裝置的技術
- 當迴圈次數是確定的,消除迴圈並使用多次函式呼叫往往更快
- 避免不必要的屬性查詢(一次查詢複雜度O(n))
// Jeff Greenberg for JS implementation of Duff's Device // 假設:values.length 0 function process(v) { alert(v); } var values = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]; var iterations = Math.ceil(values.length / 8); var startAt = values.length % 8; var i = 0; do { switch(startAt) { case 0 : process(values[i++]); case 7 : process(values[i++]); case 6 : process(values[i++]); case 5 : process(values[i++]); case 4 : process(values[i++]); case 3 : process(values[i++]); case 2 : process(values[i++]); case 1 : process(values[i++]); } startAt = 0; }while(--iterations 0);
- 達夫裝置背後的基本理念是:
- 每次迴圈中最多可8次呼叫process()函式,迴圈迭代次數為元素總數除以8
- 因為總數不一定是8的整數倍,所以startAt變數存放餘數,指出第一次迴圈中應當執行多少次process()。
- 比方說現在有12個元素,那麼第一次迴圈將呼叫process()4次,第二次迴圈呼叫process()8次,用2次迴圈代替了12次迴圈。
- tips: case語句找到第一個匹配的語句之後,未遇見break語句時,後面的語句將會依次執行。
- 03年改進版本,先處理餘數部分,幾乎增速40%
// Speed Up Your Site(New Riders, 2003) function process(v) { alert(v); } var values = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]; var iterations = Math.floor(values.length / 8); var leftover = values.length % 8; var i = 0; if(leftover 0) { do { process(values[i++]); }while(--leftover 0); } do { process(values[i++]); process(values[i++]); process(values[i++]); process(values[i++]); process(values[i++]); process(values[i++]); process(values[i++]); process(values[i++]); }while(--iterations 0);
- 注意作用域
- 避免雙重解釋
- 在以下例子中,都要解析包含JavaScript程式碼的字串
- 這是不能再初始的解析過程中完成的,因為程式碼是包含字串中的。
- 必須在程式碼執行的同時新啟動一個解析器來解析
- 例項化一個新的解析器有不容忽視的開銷
//某些程式碼求值——避免!! eval("alert('Hello world!')"); //某些程式碼求值——已修正 alert('Hello world!'); //建立新函式——避免!! var sayHi = new Function("alert('Hello world!')"); //建立新函式——已修正 var sayHi = function(){ alert('Hello world!'); }; //設定超時——避免!! setTimeout("alert('Hello world!')", 500); //設定超時——已修正 setTimeout(function(){ alert('Hello world!'); }, 500);
- 效能的其他注意事項
- 原生方法較快
- Switch語句較快
- 位運算子較快
- 可維護性
- 最小化語句數
- JavaScript程式碼中語句數量也影響所執行的操作的速度
- 完成多個操作的單個語句要比完成單個操作的多個語句快
- 多個變數宣告
//4個語句——很浪費 var count = 5; var color = "blue"; var values = [1, 2, 3]; var now = new Date(); //一個語句 var count = 5, color = "blue"; values = [1, 2, 3]; now = new Date();
- 插入迭代值
var name = values[i++];
- 使用陣列和物件字面量
//用4個語句建立和初始化陣列——浪費 var values = new Array(); values[0] = 123; values[1] = 456; values[2] = 789; //用1個語句建立和初始化陣列 var values = [123, 456, 789]; //用4個語句建立和初始化物件——浪費 var person = new Object(); person.name = "nicholas"; person.age = 29; person.sayName = function(){ alert(this.name); } //用1個語句建立和初始化物件 var person = { name = "nicholas", age = 29, sayName = function(){ alert(this.name); } }
- 優化DOM互動
- 最小化現場更新(部分更新)
- 使用innerHTML
使用時構建好一個字串然後一次性呼叫innerHTML要比呼叫innerHTML多次快得多 - 使用事件代理
可以將事件處理程式附加到更高層的地方(祖先節點)負責多個目標的事件處理。 - 減少呼叫HTMLCollection次數