非侵入式JavaScript
非侵入式JavaScript[1]是一種將JavaScript從HTML結構抽離的設計概念,避免在HTML標籤中夾雜一堆onchange、onclick等屬性去掛載JavaScript事件,讓HTML與JavaScript分離,依模型-视图-控制器的原則將功能權責清楚區分,使HTML也變得結構化容易閱讀。這個名称并不是正式定义,它的基本原则包括:
- 將网页的行为层和表现层分离开[2];
- 是解决传统JavaScript编程问题(浏览器呈现不一致,缺乏扩展性)的最佳实践;
- 为可能不支持JavaScript高级特性的用户代理(通常是浏览器)提供渐进增强的支持[3]。
行為與文件標籤的分離
傳統上,JavaScript腳本通常與HTML文件的標籤放在一起。例如,以下是在HTML中註冊JavaScript事件處理程序的典型方法:
<input type="text" name="date" onchange="validateDate()"/>
HTML標籤的目的通常是描述文件的排版結構,而不是網頁操作的程序行為。兩者的結合或許會對網站的可維護性產生負面影響,例如將呈現和內容相結合。在HTML中建立和引用的JavaScript腳本行為,例如在單一元素上設置多個不同事件的處理程序,或在多個元素上設置相同的事件處理程序,或者在使用事件委派時,結果可能難以使用和維護。
非侵入式方案是以編程方式註冊需要的事件處理程序,而不是和網頁元素內嵌在一起。不同於前述那樣添加一個onchange
屬性,相關的元素改用簡單的標識,例如以class
,id
屬性和它們值當成腳本參考的標識,或標記中一些其它的方式:
<input type="text" name="date" id="date"/>
當頁面首次加載到瀏覽器中時,執行的腳本可以尋找每個相關元素,並相對應地進行設置:
window.addEventListener("DOMContentLoaded",function() {
document.getElementById("date").addEventListener("change",function() {
//code
});
});
命名空間
非侵入式JavaScript應儘量減少將物件添加到運行環境,或全局的命名空间中。其它腳本有可能覆蓋掉全局命名空间中,所建立的任何變量或函數;而這將導致發生不預期的結果時,卻難以除錯的困擾。JavaScript並沒有內建明確的命名空间機制,但利用語言設計很容易可產生需求的效果。Flanagan建議以Java編程的開發風格,將開發人員自己的域名反轉,作為全球獨一的名前空間發佈。
var org;
if (!org) {
org = {};
} else if (typeof org != 'object') {
throw new Error("org already exists and is not an object.");
}
if (!org.example) {
org.example = {};
} else if (typeof org.example != 'object') {
throw new Error("org.example already exists and is not an object.");
}
如在上面的org对象中,便可定義各種變量和函數。但还是建議在命名空间內,使用閉包進一步隔離,作為私有的變量和函數來使用,以共用介面回傳每個函數作用的結果。上列代碼可依照以下內容,改寫為非侵入式:
org.example.Highlight = function() {
// Define private data and functions
var highlightId = 'x';
function setHighlight(color) {
document.getElementById(highlightId).style.color = color;
}
// Return public pointers to functions or properties
// that are to be public.
return {
goGreen: function() { setHighlight('green'); },
goBlue: function() { setHighlight('blue'); }
}
}(); // End closure definition and invoke it.
從任何其它的模組,可以呼叫這些共用介面的方法,如下列:
org.example.Highlight.goBlue();
var h = org.example.Highlight;
h.goGreen();
以這種方式,每個模組-開發人員的代碼都包含在私有或唯一的命名空间中,並不會干擾或侵入任何其它代碼。
最佳實務
非侵入式Javascript的本質是增加了分離的行為層概念,而且這範式的提倡者認同一些相關的原則,如下列: