將配置數(shù)據(jù)從代碼中分離出來
任何時候修改源代碼都會有引入 bug 的風險,且只修改一些數(shù)據(jù)的值也會帶來一些不必要的風險。精心設計的應用應當將關鍵數(shù)據(jù)從主要的源碼中抽離出來,因為數(shù)據(jù)是不應當影響指令的正常運行。
什么是配置數(shù)據(jù)
配置數(shù)據(jù)是應用中寫死(hardcoded)的值。
- 示例:
// 將配置數(shù)據(jù)埋藏在代碼中
function validate(value) {
if(!value) {
alert("Invalid value");
location.href = "/errors/invalid.php";
}
}
function toggleSelected(element) {
if(hasClass(element, "selected")) {
removeClass(element, "selected");
} else {
addClass(element, "selected");
}
}
解釋:
這段代碼中有三個配置數(shù)據(jù)片段:1.字符串 "Invalid value",2.URL "/errors/invalid.php",3.CSS 的 className "selected"。這三個數(shù)據(jù)在開發(fā)過程中都會被頻繁地修改。-
配置數(shù)據(jù):
- URL
- 需要展現(xiàn)給用戶的字符串
- 重復的值
- 設置(比如每頁的配置項)
- 任何可能發(fā)生變更的值
注意:
配置數(shù)據(jù)是可發(fā)生變更的,并且不希望因為需求變更,到 JavaScript 源碼中修改配置數(shù)據(jù)。
抽離配置數(shù)據(jù)
將配置數(shù)據(jù)從代碼中抽離出來的第一步是將配置數(shù)據(jù)拿到外面,即將數(shù)據(jù)從 JavaScript 代碼之中拿掉。
- 示例:
// 將配置數(shù)據(jù)抽離出來
var config = {
MSG_INVALID_VALUE : "Invalid value",
URL_INVALID : "/errors/invalid.php",
CSS_SELECTED : "selected"
};
function validate(value) {
if(!value) {
alert(config.MSG_INVALID_VALUE);
location.href = config.URL_INVALID;
}
}
function toggleSelected(element) {
if(hasClass(element, config.CSS_SELECTED)) {
removeClass(element, config.CSS_SELECTED);
} else {
addClass(element, config.CSS_SELECTED);
}
}
-
核心:
所有的配置數(shù)據(jù)都從函數(shù)中移除,并替換為 config 對象中的屬性占位符(但這可能存在另外一個問題:造成代碼分割問題)。 -
推薦:
為每個屬性加前綴,用以表明數(shù)據(jù)的類型。例如,MSG 表示展現(xiàn)給用戶的消息,URL 表示網(wǎng)絡地址,CSS 表示這是一個 className。 -
意義:
- 任何人都可以修改它們,而不會導致應用邏輯出錯。
- 將整個 config 對象放到單獨的文件中,對配置數(shù)據(jù)的修改可以完全和使用這些數(shù)據(jù)的代碼隔離開來。
保存配置數(shù)據(jù)
配置數(shù)據(jù)最好放在單獨的文件中,以便清晰地分隔數(shù)據(jù)和應用邏輯。
作者推薦使用非 JavaScript 文件形式來存儲配置數(shù)據(jù)。
【理由】:不需要遵照 JavaScript 語言的語法來阻止配置數(shù)據(jù),這樣可確保不會出語法錯誤。如果你將多個 JavaScript 文件合并成一個,一個語法錯誤就會導致整個應用程序崩潰。
【觀點】:將文件中的配置數(shù)據(jù)正確格式化是很麻煩的一件事,當你拿到這樣一個文件時,你會覺得將配置數(shù)據(jù)自動轉(zhuǎn)換為 JavaScript 格式是無足輕重的一件事。
【我的理解】:起初看到作者說 JavaScript 配置數(shù)據(jù)很麻煩,且容易出語法錯誤時不是很理解。采用對象字面量的書寫方式也不會出語法錯誤,而且書寫也不麻煩,但繼續(xù)往下閱讀到“拿到這樣一個文件時”這句話時,有些明白作者的意思了。比如說業(yè)務或設計直接丟給你一個 EXCEL 文件,一列 key,一列 value,如果要按照 JSON 的寫法,我必須給每個 key 加一對引號,然后在其后面加一個冒號,再給 value 加一對引號,最后在 value 的右引號后加一個逗號。作者推薦使用 Java 屬性文件(Java properties file)來存放配置數(shù)據(jù),形式如下:
MSG_INVALID_VALUE = Invalid value
URL_INVALID = /errors/invalid.php
CSS_SELECTED = selected
此時,我只需要先將 key 列全部復制粘貼,讓其各占一行,然后在每行后面加個等號,再復制 value 列,讓其與相匹配的 key 對應。
-
優(yōu)點:
- 書寫簡單,格式清晰。
- 不用寫引號,因此不必擔心字符串中的某些轉(zhuǎn)義字符以及字符串的結(jié)束位置。
- 編輯時可完全忽略 JavaScript 語法。
接下去的步驟是將該 Java 屬性文件轉(zhuǎn)換為 JavaScript 可用的文件。
- JSON:
{
"MSG_INVALID_VALUE": "Invalid value",
...
}
- JSONP:
{
myfunc({
"MSG_INVALID_VALUE": "Invalid value",
...
});
}
- 純 JavaScript:
var config = {
MSG_INVALID_VALUE: "Invalid value",
...
}
本書的作者創(chuàng)建了一個工具 Props2Js,用以讀取 Java 屬性文件并給出以上三種格式的輸出。
Props2Js
- 簡介:免費且開源。
- 地址:傳送門
- 用法:
java -jar props2js-0.1.0.jar --to jsonp --name myfunc
--output result.js source.properties
- 用法介紹:
- to:指定要輸出的格式,可以是“js”,“json”,“jsonp”。
- name:指定了變量名稱(當格式為“js”時)或函數(shù)名稱(當格式為“jsonp”時)。當格式為“json”時忽略這個選項。
- output:指定了輸出的文件名。
- source.properties:要讀取的文件名。