ホームページ  >  記事  >  ウェブフロントエンド  >  より安定して読みやすい JavaScript コードの作成方法を教える例

より安定して読みやすい JavaScript コードの作成方法を教える例

黄舟
黄舟オリジナル
2017-03-15 14:59:021191ブラウズ

誰もが独自の プログラミング スタイル を持っており、他の人のプログラミング スタイルを感じたり、他の人のコードを変更したりすることは避けられません。 「他人のコードを改変する」ということは、私たちにとってとても苦痛なことです。コードによっては、読みやすく保守するのがそれほど簡単ではないため、他の人に他の人のコードを変更させると、 変数 を変更するだけになる可能性があり、 関数 の呼び出しタイミングを調整するには、読み取りと保守に 1 時間またはそれ以上の時間がかかります。他の人のコードを明確にする。この記事では、位置を取得する「コンポーネント」を再構築して、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() に依存します。 $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 は

array

で説明されている動作は、states[0] を見るたびに読みにくくなります。元の作成者は毎分衝動的に、コード内の変数状態の値を常に覚えておく必要があるため、できるだけ読みやすくする必要があります。

また、上記のコードの$text.htmlは典型的なコードの重複です。今回の変更コードでは、抽出したchangeStateText()のコード位置がPromoteされていないことに注意してください。上位レベルの環境 (つまり、大規模な
クロージャ

環境全体)。

(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]) 関数で位置を取得するロジックに関連するツールのセットを作成することです。ツールプロバイダーの ID であり、これが唯一の入り口であり、コンポーネントの完全なビジネスをツールユーザーに提供する責任があります。

ここでの $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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。