編寫高質量的 JavaScript 代碼(一)

本喵又來給大家送來新鮮的讀書筆記啦.

大家感不感動? ( ´థ౪థ)

今天文章主要是來說一下,在工作中書寫 JS 時的團隊協作以及如何一些小技巧.

新的文章正在撰寫中,諸君可以回頭看看之前的文章

如何編寫高質量的 HTML 代碼

最後,求點贊,求分享,如果是女孩紙的話,哼哼,求抱抱! (づ。◕‿‿◕。)づ


以下爲正文


1.養成良好的編程習慣

1.1 團隊合作——如何避免 JS 衝突

我們進入公司之後,我們可能會從新開發一個網站.這種情況,我們定義什麼參數,使用什麼名字全部都是隨自己的想法,自己維護也可能會很正常.

但是假如我們進入公司接手的是別人的代碼呢?和其他同事一起同事合作開發呢?

這時候我們很多之前不注意的小習慣就可能會造成巨大的災難.

    <script type="text/javascript">
        var a = "li";
        var b = "peng";
        ...
    </script>

可以看到,我們在編寫 JS 的時候直接定義了兩個變量,他們的作用域都是直接在 Window 作用域下的,但是假如我們的另外一個工程師,也去直接定義了兩個變量,而且名字相同呢?

這樣會直接造成代碼的衝突,引起某些不知名的錯誤.

那我們該如何去解決呢?

我們可以使用匿名函數去對腳本進行包裹,讓變量的作用域控制於匿名函數中.

    <script type="text/javascript">
        (function(){
            var a = "li";
            var b = "peng";
            ...
        })();
    </script>   

可以看見,我們在上的代碼中使用了一個匿名函數 (function(){})();.

執行代碼的時候,包裹在這個匿名函數中的變量,它的作用域就不是 window 了,而是侷限在函數內部,這樣也就不會引起代碼衝突了.

但是這樣並不是就一勞永逸了,假如說我們在不同的腳本之間互相通信呢?

我們需要在網頁中添加新功能,在新功能中需要使用到之前定義的函數中的某一個變量,這時候該怎麼辦?

最簡單的解決方案:直接把新的代碼也放在之前的匿名函數中,但是,這樣並不符合我們的代碼規範,

而且加入之前的功能是已經離職的員工寫的呢?

你還需要首先去閱讀他之前寫的程序,去避開每一個衝突.

其次,你還需要將自己書寫的內容去進行封裝,這樣會逼死人的

(PS: 別問我我是怎麼知道的 ╮(;´༎ຶД༎ຶ`)╭ )

那麼如何去解決這個問題呢?

我們可以在 window 作用域下定義一個全局變量,把它作爲一個橋樑,完成各匿名函數之間的通信.

    <script type="text/javascript">
        var str;
    </script>
    <script type="text/javascript">
        (function(){
            var a = "li";
            str = b = "peng";
            ...
        })();
    </script>   
    <script type="text/javascript">
        (function(){
            var a = "li";
            var b = str;
            ...
        })();
    </script>   

但是我們有多個變量呢?難道需要一個個去定義麼?

我們可以使用一個 { } 對象類型的變量作爲全局變量,如果匿名函數之間需要多個變量作爲通信橋樑,可以將這些變量都作爲全局變量的屬性,這樣可以保證全局變量很少,而且拓展性很好.

    <script type="text/javascript">
        var GLOBAL = {};
    </script>
    <script type="text/javascript">
        (function(){
            var a = "li";
            var b = "peng";
            GLOBAL.str = a;
            GLOBAL.str2 = b;
            ...
        })();
    </script>   
    <script type="text/javascript">
        (function(){
            var a = GLOBAL.str;
            var b = GLOBAL.str2;
            ...
        })();
    </script>

除此之外,我們在團隊合作中,還可以將自己的名字縮寫也放在變量命名中,而且還應該去適當的寫明註釋,這些都是可以大大加快團隊合作進程的工作方式.

具體操作可以參考我之前的文章: 編寫高質量的 HTML 代碼


1.2 給程序一個統一的入口 —— window.onload 和 DOMReady

大家都知道,JS 是中腳本語言,我們的瀏覽器下載到哪裏,就會執行到哪裏.

這種特性會爲編程帶來很大的便利,但是同時也會造成代碼過於零散,四處分佈.

爲了解決這種問題,我們首先需要從功能上對程序進行職能的劃分.

網頁中的 JS 從功能上應該分爲兩大部分 —— 框架部分應用部分.

1. 框架部分提供對 JS 代碼的組織作用的代碼,其中應該包括 定義全局變量, 定義命名空間等方法.它和應用無關,每個頁面都需要包括相同的框架,所以框架部分的代碼在每個頁面都相同.

2. 應用部分提供的是頁面功能邏輯,不同頁面會有不同的功能,不同的頁面應用部分的代碼也不相同.

    <script type="text/javascript">
        function init(){

            (function(){
                ...
            }());

            (function(){
                ...
            }());

            (function(){
                ...
            }());

            (function(){
                ...
            }());
        }
    </script>

可以看見,我們將所有應用部分的代碼都集中到 init 函數內了,所有的初始化工作都在這裏,這裏就是網頁程序的入口.

但是需要注意,如果程序控制某個 DOM 節點,而該 DOM 節點當時還沒有被載入,程序會直接報錯.

有兩種解決方案,第一種最簡單的解決方案,直接把腳本放在後面.

但是有時候,我們希望我們的程序能夠無視這種放置規則,可以讓程序的位置在 DOM 節點之前或者之後.

這時候我們可以去 監聽 window 對象的 onload 事件,當 window 觸發 onload 事件之後去調用腳本.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script type="text/javascript">
        function init(){
            alert(document.getElementById("test").innerHTML);
        }
        window.onload = init;
    </script>
</head>
<body>
    <div class="test">MR_LP</div>
</body>
</html>

這樣,我們的腳本不會立即執行,而是在 window.onload 之後纔去執行.

而 window 對象會在頁面內元素全部加載完成之後纔去觸發 onload 事件,而這時候我們的 test 已經加載完畢,所以並不會報錯.

你以爲現在就可以萬事大吉了麼? 當然不是. ٩(๑˃̌ۿ˂̌๑)۶

如果頁面加載的時候,存在某張超級大的圖片呢?

window.onload 會等全部加載完成纔會觸發,難度這期間就讓用戶等着?

這時候就要說到 DOMReady 了.

DOMReady 只判斷頁面內所有的 DOM 節點 是否已經全部生成,至於節點中的內容是否已經加載,並不會檢查.

所以 DOMReady 會 比 window.onload 加載速度要快很多.

但是需要注意, DOMReady 並不是原生 JS 支持的事件,一般我們都是結合 JS 框架去使用.

如 JQ.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script type="text/javascript" scr="http://ajax.googleAPIs.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
    <script type="text/javascript">
        function() init{
            alert(document.getElementById("test").innerHTML);
        }
        $(document).ready(init);
    </script>
</head>
<body>
    <div class="test">MR_LP</div>
</body>
</html>

當然我們也可以自己去模擬 DOMReady ,即我們去定義了 init 函數,之後等<body>之前的時候去調用一下 init 函數,這時候雖然 DOM 節點不一定都全部加載完成了,但是卻一定都生成了,通過這種方式,可以去簡單模擬一下 DOMReady.

完事了? 當然沒有 (இдஇ) .

在實際工作中,網站的頭部和尾部經常會做成獨立的文件,用服務器端語言 include 到網頁中,所以我們的網頁經常會拆散成三個文件,頭部,主體和尾部三個文件.

一般來說,頭尾文件都非常穩定.因爲全站公用的統一結尾,這部分不會經常修改,而主體部分是每個頁面各不相同的,如果有的頁面不需要 JS, 這時候我們的主體中可能就沒有 init 函數了,這時候調用就肯定會報錯了.

這時我們當然可以去做一個規範,讓每個頁面都去書寫一次,但是這並不合理.

正確的處理方式是我們在書寫 init 之前可以先去判斷一下 init 是否存在.

    if(init){
        init();
    }

這樣就可以有效的避免上述問題了.

1.3 CSS 放頁頭, JS 放頁尾

CSS 放在頁頭,在載入 HTML 元素之前先載入,這樣可以避免 HTML 出現無樣式狀態.

JS 放在頁尾,可以避免 JS 阻塞網頁的呈現,減少頁面空白的時間.

1.4 文件壓縮

在之前的文章中曾經說明過,css 發佈前需要進行壓縮.

可以參考我之前的文章: 編寫高質量的 HTML 代碼

同樣的, JS 部分我們也可以去進行一下壓縮,這裏推薦兩個工具

Packers: packer

YUI Compressor: Compressor

需要注意 YUI 需要下載 jar 文件到本地,之後通過命令行調用,

好處是 YUI 不僅僅可以壓縮 JS,還可以壓縮 css.

下期預告:
JavaScript 的分層概念和 JavaScript 庫

二維碼.jpg

發佈了90 篇原創文章 · 獲贊 221 · 訪問量 36萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章