搜尋
首頁web前端js教程教你寫更穩定、可讀性強的JavaScript程式碼的範例

每個人都有自己的程式風格,也無可避免的要去感受別人的程式風格-修改別人的程式碼。 「修改別人的程式碼」對於我們來說的一件很痛苦的事情。因為有些程式碼並不是那麼容易閱讀、可維護的,讓另一個人來修改別人的程式碼,或許最後只會修改一個變數,調整一個函數的呼叫時機,卻需要花上1小時甚至更多的時間來閱讀、縷清別人的程式碼。本文一步步帶你重構一段獲取位置的」元件」——提升你的javascript程式碼的可讀性和穩定性。

本文內容如下:

  • 分離你的javascript程式碼

  • 函數不應該過度依賴外部環境

  • 語意化和重複使用

  • #元件應該專注於邏輯,行為只是封裝

  • 形成自己的風格的程式碼

#分離你的javascript程式碼

下面一段程式碼示範了難以閱讀/修改的程式碼:

(function (window, namespace) {
    var $ = window.jQuery;
    window[namespace] = function (targetId, textId) {
        //一个尝试复用的获取位置的"组件"
        var $target = $('#' + targetId),//按钮
            $text = $('#' + textId);//显示文本
        $target.on('click', function () {
            $text.html('获取中');
            var data = '北京市';//balabala很多逻辑,伪代码,获取得到位置中
            if (data) {
                $text.html(data);
            } else
                $text.html('获取失败');
        });
    }
})(window, 'linkFly');

這一段程式碼,我們暫且認可它已經構成一個」元件」。
上面的程式碼就是典型的一個方法搞定所有事情,一旦填充上內部的邏輯就會變得生活不能自理,而一旦增加需求,例如獲取位置返回的數據格式需要加工,那麼就要去裡面尋找處理資料的程式碼然後修改。

我們分離一下邏輯,得到程式碼如下:

(function (window, namespace) {
    var $ = window.jQuery,
        $target,
        $text,
        states= ['获取中', '获取失败'];
    function done(address) {//获取位置成功
        $text.html(address);
    }
    function fail() {
        $text.html(states[1]);
    }
    function checkData(data) {
        //检查位置信息是否正确
        return !!data;
    }
    function loadPosition() {
        var data = '北京市';//获取位置中
        if (checkData(data)) {
            done(data);
        } else
            fail();
    }
    var init = function () {
        $target.on('click', function () {
            $text.html(states[0]);
            loadPosition();
        });
    };
    window[namespace] = function (targetId, textId) {
        $target = $('#' + targetId);
        $text = $('#' + textId);
        initData();
        setData();
    }
})(window, 'linkFly');

函數不應該過度依賴外部環境

上面的程式碼中,我們已經把整個元件,切割成了各種函數(注意這裡我說的是函數,不是方法),這裡常出現一個新的問題:函數過度依賴不可控的變數。

變數$target和$text身為環境中的全域變量,從元件初始化便賦值,而我們切割後的程式碼大多數的操作方法都依賴$text,尤其是$text和done() 、fail()之間曖昧的關係,一旦$text相關的結構、邏輯改變,那麼我們的程式碼將會進行不小的改變。

和頁面/DOM相關的都是不可信賴的(例如$target和$text),一旦頁面結構改變,它的行為很大程度上也會隨之改變。而函數也不應該依賴外在的環境。
在不可控的變數上,我們應該解開函數和依賴變數上的關係,讓函數變得更專注自己區域的邏輯,更加的純粹。簡單的說:函數所依賴的外部變量,都應該透過參數傳遞到函數內部。
新的程式碼如下:

(function (window, namespace) {
    var $ = window.jQuery;
    //检查位置信息是否正确
    function checkData(data) {
        return !!data;
    }
    //获取位置中
    function loadPosition(done, fail) {
        var data = '北京市';//获取位置中
        if (checkData(data)) {
            done(data);
        } else
            fail();
    }
    window[namespace] = function (targetId, textId) {
       var  $target = $('#' + targetId),
            $text = $('#' + textId);
        var states = ['获取中', '获取失败'];
        $target.on('click', function () {
            $text.html(states[0]);
            loadPosition(function (address) {//获取位置成功
                $text.html(address);
            }, function () {//获取位置失败
                $text.html(states[1]);
            });
        });
    }
})(window, 'linkFly');

語意化與重複使用

變數states是一個陣列,它所描述的行為難以閱讀,每次看到states [0]都有一種分分鐘想捏死原作者的衝動,因為我們總是要記住變數states的值,在程式碼上,我們應該盡可能讓它可以很好的被閱讀。

另外,上面的程式碼中$text.html就是典型的程式碼重複,我們再一次的修改程式碼,請注意這次修改的程式碼中,我們所抽離的changeStateText()的程式碼位置,它並沒有被提升到上一層環境(也就是整個大閉包的環境)。

(function (window, namespace) {
    var $ = window.jQuery;
    function checkData(data) {
        return !!data;
    }
    function loadPosition(done, fail) {
        var data = '北京市';//获取位置中
        if (checkData(data)) {
            done(data);
        } else
            fail();
    }
    window[namespace] = function (targetId, textId) {
        var $target = $('#' + targetId),
            $text = $('#' + textId),
            changeEnum = { LOADING: '获取中', FAIL: '获取失败' },
            changeStateText = function (text) {
                $text.html(text);
            };
        $target.on('click', function () {
            changeStateText(changeEnum.LOADING);
            loadPosition(function (address) {
                changeStateText(address);
            }, function () {
                changeStateText(changeEnum.FAIL);
            });
        });
    }
})(window, 'linkFly');

提及語意化,我們必須要知道目前整個程式碼的邏輯和語意:

在這整個元件中,所有的函數模組可以分為:工具和工具提供者。

上一層環境(整個大閉包)在我們的業務中扮演著工具的身份,它的任務是締造一套和獲取位置邏輯相關的工具,而在window[namespace])函數中,則是工具提供者的身份,它是唯一的入口,負責提供組件完整的業務給工具的使用者。
這裡的$text.html()在邏輯上並不屬於工具,而是屬於工具提供者使用工具後所得到的回饋,所以changeStateText()函數置於工具提供者window[namespace]()中。

组件应该关注逻辑,行为只是封装

到此为止,我们分离了函数,并让这个组件拥有了良好的语义。但这时候来了新的需求:当没有获取到位置的时候,需要进行一些其他的操作。这时候会发现,我们需要window[namespace]()上加上新的参数。
当我们加上新的参数之后,又被告知新的需求:当获取位置失败了之后,需要修改一些信息,然后再次尝试获取位置信息。
不过幸好,我们的代码已经把大部分的逻辑抽离到了工具提供者中了,对整个工具的逻辑影响并不大。
同时我们再看看代码就会发现我们的组件除了工具提供者之外,没有方法(依赖在对象上的函数)。也就是说,我们的组件并没有对象。

我见过很多人的代码总是喜欢打造工具提供者,而忽略了工具的本质。迎合上面的增加的需求,那么我们的工具提供者将会变得越来越重,这时候我们应该思考到:是不是应该把工具提供出去?

让我们回到最初的需求——仅仅只是一个获取位置的组件,没错,它的核心业务就是获取位置——它不应该被组件化。它的本质应该是个工具对象,而不应该和页面相关,我们从一开始就不应该关注页面上的变化,让我们重构代码如下:

(function (window, namespace) {
    var Gps = {
        load: function (fone, fail) {
            var data = '北京市';//获取位置伪代码
            this.check(data) ?
                done(data, Gps.state.OK) :
                fail(Gps.state.FAIL);
        },
        check: function (data) {
            return !!data;
        },
        state: { OK: 1, FAIL: 0 }
    };
    window[namespace] = Gps;
})(window, 'Gps');

在这里,我们直接捏死了工具提供者,我们直接将工具提供给外面的工具使用者,让工具使用者直接使用我们的工具,这里的代码无关状态、无关页面。

至此,重构完成。

形成自己风格的代码

之所以讲这个是因为大家都有自己的编程风格。有些人的编程风格就是开篇那种代码的…
我觉得形成自己的编程风格,是建立在良好代码的和结构/语义上的。否则只会让你的代码变得越来越难读,越来越难写。
****
单var和多var
我个人是喜欢单var风格的,不过我觉得代码还是尽可能在使用某一方法/函数使用前进行var,有时候甚至于为了单var而变得丧心病狂:由于我又过分的喜爱函数表达式声明,函数表达式声明并不会在var语句中执行,于是偶尔会出现这种边声明边执行的代码,为了不教坏小朋友就不贴代码了(我不会告诉你们其实是我找不到了)。

对象属性的屏蔽
下面的代码演示了两种对象的构建,后一种通过闭包把内部属性隐藏,同样,两种方法都实现了无new化,我个人…是不喜欢看见很多this的..但还是推荐前者。

(function () {
    //第一种,曝露了_name属性
    var Demo = function () {
        if (!(this instanceof Demo))
            return new Demo();
        this._name = 'linkFly';
    };
    Demo.prototype.getName = function () {
        return this._name;
    }

    //第二种,多一层闭包意味内存消耗更大,但是屏蔽了_name属性
    var Demo = function () {
        var name = 'linkFly';
        return {
            getName: function () {
                return name;
            }
        }
    }
});

巧用变量置顶[hoisting]
巧用函数声明的变量置顶特性意味着处女座心态的你放弃单var,但却可以让你的函数在代码结构上十分清晰,例如下面的代码:

(function () {
    var names = [];
    return function (name) {
        addName(name);
    }
    function addName(name) {
        if (!~names.indexOf(name))//如果存在则不添加
            names.push(name);
        console.log(names);// ["linkFly"]
    }
}())('linkFly');

if和&&
这种代码,在几个群里都见过讨论:

(function () {
    var key = 'linkFly',
        cache = { 'linkFly': 'http://www.cnblogs.com/silin6/' },
        value;
    //&&到底
    key && cache && cache[key] && (value = cache[key]);
    //来个if
    if (key && cache && cache[key])
        value = cache[key];
})();

以上是教你寫更穩定、可讀性強的JavaScript程式碼的範例的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
JavaScript框架:為現代網絡開發提供動力JavaScript框架:為現代網絡開發提供動力May 02, 2025 am 12:04 AM

JavaScript框架的強大之處在於簡化開發、提升用戶體驗和應用性能。選擇框架時應考慮:1.項目規模和復雜度,2.團隊經驗,3.生態系統和社區支持。

JavaScript,C和瀏覽器之間的關係JavaScript,C和瀏覽器之間的關係May 01, 2025 am 12:06 AM

引言我知道你可能會覺得奇怪,JavaScript、C 和瀏覽器之間到底有什麼關係?它們之間看似毫無關聯,但實際上,它們在現代網絡開發中扮演著非常重要的角色。今天我們就來深入探討一下這三者之間的緊密聯繫。通過這篇文章,你將了解到JavaScript如何在瀏覽器中運行,C 在瀏覽器引擎中的作用,以及它們如何共同推動網頁的渲染和交互。 JavaScript與瀏覽器的關係我們都知道,JavaScript是前端開發的核心語言,它直接在瀏覽器中運行,讓網頁變得生動有趣。你是否曾經想過,為什麼JavaScr

node.js流帶打字稿node.js流帶打字稿Apr 30, 2025 am 08:22 AM

Node.js擅長於高效I/O,這在很大程度上要歸功於流。 流媒體匯總處理數據,避免內存過載 - 大型文件,網絡任務和實時應用程序的理想。將流與打字稿的類型安全結合起來創建POWE

Python vs. JavaScript:性能和效率注意事項Python vs. JavaScript:性能和效率注意事項Apr 30, 2025 am 12:08 AM

Python和JavaScript在性能和效率方面的差異主要體現在:1)Python作為解釋型語言,運行速度較慢,但開發效率高,適合快速原型開發;2)JavaScript在瀏覽器中受限於單線程,但在Node.js中可利用多線程和異步I/O提升性能,兩者在實際項目中各有優勢。

JavaScript的起源:探索其實施語言JavaScript的起源:探索其實施語言Apr 29, 2025 am 12:51 AM

JavaScript起源於1995年,由布蘭登·艾克創造,實現語言為C語言。 1.C語言為JavaScript提供了高性能和系統級編程能力。 2.JavaScript的內存管理和性能優化依賴於C語言。 3.C語言的跨平台特性幫助JavaScript在不同操作系統上高效運行。

幕後:什麼語言能力JavaScript?幕後:什麼語言能力JavaScript?Apr 28, 2025 am 12:01 AM

JavaScript在瀏覽器和Node.js環境中運行,依賴JavaScript引擎解析和執行代碼。 1)解析階段生成抽象語法樹(AST);2)編譯階段將AST轉換為字節碼或機器碼;3)執行階段執行編譯後的代碼。

Python和JavaScript的未來:趨勢和預測Python和JavaScript的未來:趨勢和預測Apr 27, 2025 am 12:21 AM

Python和JavaScript的未來趨勢包括:1.Python將鞏固在科學計算和AI領域的地位,2.JavaScript將推動Web技術發展,3.跨平台開發將成為熱門,4.性能優化將是重點。兩者都將繼續在各自領域擴展應用場景,並在性能上有更多突破。

Python vs. JavaScript:開發環境和工具Python vs. JavaScript:開發環境和工具Apr 26, 2025 am 12:09 AM

Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器