前言
之前我做過一個web app(原來可以這么叫啦),在一個頁面上有很多小窗口,每個小窗口都是獨立的應用,比如:
① 我們一個小窗口數據來源是騰訊微博,需要形成騰訊微博app小窗口
② 我們一個小窗口數據來源新浪微博,需要形成新浪微博的小窗口
我們注意到以上2個的數據源與處理方式較一致,但是需要做處理,而且其鑒權也不盡相同,所以這個js代碼有相同的,也有不相同的。
③ 我們的一個小窗口數據來源於百度RSS,需要形成點擊標題展開的功能
④ 我們一個小窗口數據來源於XXX,其表現形式為選項卡......
⑤ 我們一個小窗口是flash,需要......
⑥ 我們一個小窗口是個綜合應用,里面還會有定時器,自動的更新其數據
......
① 點擊最大化圖標會最大化窗口,里面的數據滾屏分頁
② 拖動排序,點擊選擇圖標分配(導航上有不同的類)
③ 新聞預覽,類似於google效果
④ 延遲加載
......
各位,這些功能都在一個頁面呢,我們的js該怎么組織了,我們的js要怎么寫才能讓后來的人讀的清晰呢?
然后,響應式布局流行了,小葉你去搞下,實現響應式布局!
然后,瀑布流很火,小葉不然把瀑布流也加上
然后,純屏設計出來了,小葉,將我們的程序設置一下吧,用戶可以選擇自己想要的。。。
......
我們知道一個網站干不了這么多事情,但是一個公司不是研發最大,不是產品最大,而是老板最大!
老板說需要,那就必須需要,你不行就閃開,有人行。
我們這里先不說風雲變幻的需求,就說以上應用,面對不停增加的不停種類的小窗口,我們應當如何組織,並且控制我們的javascript代碼呢???
javascript之路
javascript最初使用並沒有那么復雜,基本就是一個頁面一個js解決問題,但是現在情況變了,我們的js現在需要干的事情不比后端少了,而且還有越來越多的趨勢!
在這個時候很多后端的東西便直接上來了:
① MVC
② MVVM
③ 模塊化編程
④ 設計模式
以上的提出都是為了更好的幫助前端兄弟組織自己的代碼,但是我們知道一個事實:
設計模式這個東西沒有幾年扎實的功底根本就達不到一個高度,比如本人,在剛畢業時候還在搞.net便看了幾本設計模式的書籍,自以為有所得,現在想來,尼瑪的神馬都不記得了!!!
所以,一個事實,前端很多兄弟,並且是比較優秀的兄弟,對設計模式了解不夠深入啦(我反正不深)。
從優秀到高手的蛻變中,我們會寫大量js代碼,我們會發現,尼瑪這一坨代碼和那一坨代碼好像長得有點像,
尼瑪這三塊代碼感覺就只有一點差距啦!於是小釵就干過這個事情:
看着js里面有幾塊相同的,然后將它和到一個函數中了,並在函數中做了一點點變化,實現功能了,小釵看到少了幾十行代碼,小釵感到很高興。
於是慢慢小釵在編程過程中有意無意的發現每次都會有幾個家伙會重復,所以有一天小釵終於決定將至封裝一番,從那以后,小釵遇到這個問題變不會寫多余的代碼了。
其實,通過以上的做法,優秀的程序員慢慢有了模塊化編程的思想,或者面向對象編程的思維,剛開始以實現了很多的插件沾沾自喜,到后面點,就會站在框架與js/css代碼的組織的高度審視整個項目的實現了。
這個時候他便是高手啦,但是有一段很長的路要走。。。
模塊化編程
javascript時不存在類這種說法的,所以模塊(module)就是一個傳說(ECMAScipt第六版表示會支持)。
但是我們偉大的前端技術人員模擬實現了類這個家伙,最后還實現了模塊這個家伙。
最初的想法:模塊就是實現特定功能的一組方法
1 function m1() {} 2 function m2() {}
將上面兩個函數加在一起,便可直接調用,但是我們知道這種做法會導致全局對象污染,所以我們換個做法:
1 var person = { 2 name: '葉小釵', 3 getName: function () {}, 4 setName: function () {} 5 };
這樣做又會導致內部的局部變量會被外部篡改,這顯然不夠“oop”,我們知道javascript唯一可以產生局部作用域的方式便是函數,所以我們有了這種寫法:
1 var Person = (function () { 2 3 var name='葉小釵'; 4 var getName: function () {}; 5 var setName: function () {}; 6 7 return {get: getName, set: setName}; 8 9 })();
如此一來,我們內部的的變量就老實了,這樣看上去也比較面向對象啦。
以上就是我們模塊化編程的基本做法,下面來一點點變化,因為我們的模塊可能會很大的:
當模塊很大時,便需要用到“放大模式”,這些高級概念我們后面點再去理解。
1 var person = (function (mod) { 2 3 mod.getAge = function () {}; 4 5 ...... 6 7 })(Person);
我們看到我們原來是沒有age這個變量的,所以我們一個模塊需要用到的變量最好能在上面定義。
異步問題
以上的方式其實比較樂觀,但是我們很多時候其實並不能保證person已經被定義了,所以上面的用法可能是錯誤的,這在異步編程模型中會經常遇到,這個時候我們有了一個“寬放大模式”:
1 var person = (function (mod) { 2 3 mod.getAge = function () {}; 4 5 ...... 6 7 })(Person || {});
做了一點點的變化,但是整個程序的容錯度上升了。
模塊化的重要性
模塊化后,我們可以方便的使用其他同事的代碼,也不必擔心命名污染的問題了,目前通行的javascript模塊規范有兩種:CommonJS與AMD。
node.js這一神器的產物的誕生(我后面點會針對此寫一個系列的文章,在此叮囑自己),標志着javascript模塊化編程正式誕生,因為網頁一般不會很復雜,服務器的話,沒有模塊便做死吧。。。。
node.js的模塊系統是參照CommonJS規范實現的,在CommonJS中有一個全局性方法require(),用於加載模塊。
若是有一數學模塊math.js,便可以如此解決:
1 var math = require('math'); 2 math.add(1, 4);
若是要搞node.js的兄弟先從這個家伙開始吧。
客服端的疑惑
以上的代碼,我們知道第一行其實是會加載一段math.js的函數的,意思是我們下面的math.add要等到文件加載結束才行啦。。。這就是同步加載與異步加載的痛苦。
我們知道好的網站是不能容忍“假死”的,但是我們並不能知道網速等因素,所以同步的話,瀏覽器必定會假死,異步加載模型再一次出現{asynchronous},傳說中的AMD。
AMD:Asynchronous Module Definition
異步模塊定義,他采用異步方式加載模塊,模塊加載不影響后面語句執行,其實我們對他的實現應該非常熟悉的,想想我們的ajax啦:
1 require('math', function (math) { 2 math.add(); 3 });
這個內部發生了什么大家應該一目了然,應該和$.getScript是一個原理的。於是我們來介紹一個實現了AMD的javascript庫:require.js。
PS:初步印象,這樣雖然是按需加載的,但是以我們之前小窗口的需求來說,我們可能每一個小窗口會對應一個js文件,頁面小窗口過多(延遲加載可以忽略),可能導致同時加載幾個js會不會對性能有影響嗎?這里我們先不關注他。
我們來看看我們的require.js,他的提出為了解決以下問題:
① 實現javascript異步加載,避免頁面假死
② 管理模塊之間的依賴性,便於代碼編寫與維護(這是重點啊)
要使用require.js需要下載最新的版本。這里比較重要,我們單獨開一段吧
require.js
我們先去官網下載腳本:http://requirejs.org/docs/release/2.1.6/r.js
他這個最讓人興奮的就是,我們可以如此指定一個頭main入口文件:
<script src="js/require.js" data-main="js/main"></script>
比如我現在會一次性加載幾個js文件:
1 require (['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){ 2 // some code here 3 });
以上是主模塊依稀三個模塊的寫法,若是主模塊依賴於jquery的話:
require(['jquery'], function ($) { });
AMD模塊寫法
require.js加載采用AMD規范,假定有一個math.js文件,他定義了一個math模塊,那么math需要這樣寫:
//math.js define(function () { var func = function () {}; return {func: func}; }); //加載方式 require(['math'], function (math) { //... })
算了,關於require.js這塊東西,我等下做幾個例子再跟進吧,現在都不熟悉,說這么多也沒用。
結語
這塊東西我們暫時說道這里,接下來我們來使用一番require.js,以及來說下MVC與MVVM是神馬東西吧。
參考:
