前端項目怎樣合理使用模塊化和閉包?
一. 開發中遇到的問題
通常我們在做項目的時候一般會出現這樣的一種情況。
<script> // a.js var varity=1; function changeHTML(){ //define function changeHTML } function decodeHTML(){ // define function decodeHTML } //……………… </script>
main.html的引入
<html> <body></body> <script src="a.js"></script> </html>
這個按照我們正常的寫法上面來說是沒有什麽問題的,至少在使用上面沒有問題,但是卻存在一些隱患
1. 假設後來有A同事需要添加一個方法叫做decodeString來處理string文本,B同事如果也要添加一個類似的方法,那麽就不能夠使用decodeString來命名,除此之外這樣的函數定義也會直接把函數暴露到全局中。
2. 變量也會被散亂分布到全局變量中,後續變量命名就會有命名沖突的隱患
3. 如果是函數與函數之間的依賴關系比較難維護等問題
二、初級的解決方案
對於這樣的一種情況最開始谷歌的YUI提出的解決方案是與PHP,JAVA的解決方案相似就是添加一個命名空間。
上面的代碼我們可以這樣的去編寫。
<script> // a.js // 變量 var variable={};//全局中只有唯一的一個variable,用來保存所有的變量 variable.varity=1; // 方法 var methods={};//全局中只有唯一的一個methods,用來保存所有的方法
var methods.common={};methods.common.changeHTML=function(){ //define function changeHTML
alert(1);
} methods.common.decodeHTML = function () { //define function decodeHTML } </script>
我們發現這樣的基本上面的這種方法是可以解決一些不必要的沖突的(除非你是想給自己挖坑),假如我們要添加一個關於用戶登錄的方法,我們可以這樣寫。
methods.users = {}; methods.users.login=function(str){ console.log(str); } methods.users.login("this is a test");
這樣去管理方法和變量雖然相比於第一種方法來說可以有效的解決沖突,但是也是存在如下的一些問題:
1. 如果我們要調用這個簡單的login方法,我們會發現需要書寫一大串的前綴(methods.users.login)。代碼編寫風格不簡潔
2. 變量雖然是可以有效的管理,但是確實沒有解決讀寫的控制,特別是如果團隊的人較多的話,容易發生誤操作,所以應該進行讀寫分離。
三、進一步的解決方案
變量的管理方案----閉包
其實上面對變量的管理已經比較有效了,但只是缺少讀寫的控制,容易發生誤操作,所以參照ES6的做法,重新編寫了一個getter方法和setting方法來獲取參數。
var val=function(){ var that=this; var variable={}; variable.varity=1; var returnVal={}; this.isString=function(str){ try { if (typeof str !== "string") { throw "TypeErr"; }else{ return true; } } catch (e) { if (e == "TypeErr") { return false; } } } returnVal.getter=function(str){ var isStr=that.isString(str); if(isStr){ return variable[str]; }else{ console.error("input type must string!!!!!"); } } returnVal.setter=function(key,value){ var isStr=that.isString(key); if(isStr){ if(variable[key]==undefined){ eval(variable[key]); } variable[key]=value; }else{ console.error("input type must string!!!!!"); } } return returnVal; }
運行代碼測試:
var val= val();//初始化方法 console.log(val.getter("varity"));// 1 val.setter("va222rity",3);//不存在重新添加並賦值 console.log(val.getter("va222rity")); // 3
現在這樣寫變量就不容易發生誤操作了(讀寫已經分離),也不會把變量泄漏到全局中去。
上面的函數就是對閉包的一個實際的應用。具體不懂的可以自行百度閉包的知識(具體還可以實現的更加的簡潔,在這裏不累贅)。
變量相關的優化方案我們已經說了,我們接下來說一說關於函數模塊化的應用。
函數的管理方案-------模塊化
模塊化最早是由node.js提出來的一種規範,具體的實現是CommonJS
但是由於服務器端與瀏覽器端的不同,不同之處主要表現在服務器端加載文件是通過緩存讀取本地文件的形式來實現的,所以加載的時間可以忽略不計,但是在瀏覽器端(前端)卻不是這樣的,每個文件都是通過HTTP請求從服務器中下載而來,所以中間會產生一定的加載時間,所以瀏覽器端和服務器端你是不同的。
服務器端
采用的方式是按需加載,也就是說什麽時候需要就什麽時候加載這個文件進來
瀏覽器端
共同點:都是實行對代碼的預先加載
異同點:RequireJS提出的觀點是預先加載並執行[早期],SeaJS提出的觀點是預先加載,按需執行。
相比之下,作者更傾向於RequireJS的實現方式,具體原因如下
1.RequireJS社區和文檔的支持比較完善
2,SeaJS項目停止維護
3.RequireJS在後續的版本中含括了SeaJS的功能
在實際的應用之中,一般模塊化是用來解決以下的幾種情況的:
1. 解決文件與文件之間相互的依賴關系所產生的問題,方便後期代碼的升級維護。
2. 解決過渡加載不需要的函數代碼
3. 函數直接不會泄漏到全局
具體的用法不過多的解釋不懂點這裏:http://www.zhangxinxu.com/sp/seajs/docs/zh-cn/module-definition.html#define
四、小結
寫這篇文章的時候已經是2018年了,這些東西雖然可以用,但是未免有些過時。
該文章主要是講關於閉包和模塊化在項目中要怎樣的合理使用,目前模塊化最好的解決方案我認為是ES6的module。
但是考慮到團隊中可能水平參差不齊,導致ES6推動的難度。所以建議首選ES6,次選RequireJS。
關於ES6的講解介紹會在之後的文章提及,如果覺得文章對你有幫助請點個贊。
前端項目怎樣合理使用模塊化和閉包?