以前我作過一個web app(原來能夠這麼叫啦),在一個頁面上有不少小窗口,每一個小窗口都是獨立的應用,好比:javascript
① 咱們一個小窗口數據來源是騰訊微博,須要造成騰訊微博app小窗口css
② 咱們一個小窗口數據來源新浪微博,須要造成新浪微博的小窗口前端
咱們注意到以上2個的數據源與處理方式較一致,可是須要作處理,並且其鑑權也不盡相同,因此這個js代碼有相同的,也有不相同的。java
③ 咱們的一個小窗口數據來源於百度RSS,須要造成點擊標題展開的功能node
④ 咱們一個小窗口數據來源於XXX,其表現形式爲選項卡......jquery
⑤ 咱們一個小窗口是flash,須要......程序員
⑥ 咱們一個小窗口是個綜合應用,裏面還會有定時器,自動的更新其數據web
......ajax
① 點擊最大化圖標會最大化窗口,裏面的數據滾屏分頁編程
② 拖動排序,點擊選擇圖標分配(導航上有不一樣的類)
③ 新聞預覽,相似於google效果
④ 延遲加載
......
各位,這些功能都在一個頁面呢,咱們的js該怎麼組織了,咱們的js要怎麼寫才能讓後來的人讀的清晰呢?
而後,響應式佈局流行了,小葉你去搞下,實現響應式佈局!
而後,瀑布流很火,小葉否則把瀑布流也加上
而後,純屏設計出來了,小葉,將咱們的程序設置一下吧,用戶能夠選擇本身想要的。。。
......
咱們知道一個網站幹不了這麼多事情,可是一個公司不是研發最大,不是產品最大,而是老闆最大!
老闆說須要,那就必須須要,你不行就閃開,有人行。
咱們這裏先不說風雲變幻的需求,就說以上應用,面對不停增長的不停種類的小窗口,咱們應當如何組織,而且控制咱們的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須要下載最新的版本。這裏比較重要,咱們單獨開一段吧
咱們先去官網下載腳本: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是神馬東西吧。
參考: