JavaScriptチェーン構造のシリアル化の詳細説明

黄舟
リリース: 2017-03-04 15:21:22
オリジナル
1100 人が閲覧しました

1. 概要

JavaScript には、次のようなチェーン パターン コードが多すぎます。それを平らにしてチェーンで処理したい場合はどうすればよいですか?以下の通りです:

if(...){
    //TODO
}else if(...){
    //TODO
}else{
    //TODO
}
ログイン後にコピー

一緒に実装してみましょう。

2. チェーン コードをフラット化する

今、次のチェーン コードがあるとします。

switch(name){
    case ...:{
        //TODO
        break;
    }
    case ...:{
        //TODO
        break;
    }
    default:{
        //TODO    
    }
}
ログイン後にコピー

それでは、段階的に「フラット化」していきます。

実際、上記のコードを見ると、if...else 形式が実際にはデータ構造内の単一リンク リストであることがわかります。次に、次のように、最初に JavaScript を使用して単一リンク リストを実装します。 :

//fn1,f2,f3为处理函数
_if(fn1)._elseIf(fn2)._else(fn3);
ログイン後にコピー
ログイン後にコピー

ここで、f1、f2、f3 は判定関数であり、f1、f2、f3 が 'next' を返した場合は下方向の検索を続行し、そうでない場合は下方向の検索を停止すると仮定します。以下の通り:

if(name === 'Monkey'){
    console.log('yes, I am Monkey');
}else if(name === 'Dorie'){
    console.log('yes, I am Dorie');
}else{
    console.log('sorry, over for ending!');
}
ログイン後にコピー

さて、これがリンクリストのパターンです。

しかし、

私たちの最終目標は次のことを達成することですか?

var thens = [];
thens.resolve = function(name){
    for(var i = 0, len = this.length; i < len;i++){
        if(this[i](name) !== &#39;next&#39;){
            break;
        }
    }
}
thens.push(f1, f2, f3);
ログイン後にコピー

上記のコードを次のように変更すれば良いのではないかと思われるかもしれません。 ! !

function f1(name){
    if(name === &#39;Monkey&#39;){
        console.log(&#39;yes, I am Monkey&#39;);
    }else{
        return &#39;next&#39;;
    }
}
function f2(name){
    if(name === &#39;Dorie&#39;){
        console.log(&#39;yes, I am Dorie&#39;);
    }else{
        return &#39;next&#39;;
    }
}
function f3(){
    console.log(&#39;sorry, over for ending!&#39;);
}
ログイン後にコピー

しかし、

JavaScript の Push メソッドは、配列オブジェクトではなく、配列の新しい長さを返します。

したがって、

その後は、新しい add メソッドを作成することしかできません。このメソッドは、push と同じ効果がありますが、配列オブジェクトを返します。以下のように:

//fn1,f2,f3为处理函数
_if(fn1)._elseIf(fn2)._else(fn3);
ログイン後にコピー
ログイン後にコピー

テストコードは次のとおりです:

thens.push(f1).push(f2).push(f3).resolve();
ログイン後にコピー

ただし、これには欠点があり、配列を作成するたびに add メソッドとsolveメソッドをグローバル変数にバインドすることができません。 .メソッドなので、リファクタリングされたコードは次のようになります:

thens.add = function(f){
    if(typeof f === &#39;function&#39;){
        this.push(f);
        return this;        
    }        
}
ログイン後にコピー
明らかに、add やsolve などのパブリック メソッドがインスタンス化されるたびに作成されるのは非科学的です。そのため、次のようにプロトタイプを使用して元のベースで変形を続けます。 :

var thens = [];
thens.add = function(f){
    if(typeof f === &#39;function&#39;){
        this.push(f);
        return this;        
    }        
}
thens.resolve = function(name){
    for(var i = 0, len = this.length; i < len;i++){
        if(this[i](name) !== 'next'){
            break;
        }
    }    
}
thens.add(f1).add(f2).add(f3).resolve();
ログイン後にコピー

テストコードは以下の通りです:

function Slink(){
    this.thens = [];
    this.thens.add = function(f){
        if(typeof f === &#39;function&#39;){
            this.push(f);
            return this;        
        }        
    }
    this.thens.resolve = function(name){
        for(var i = 0, len = this.length; i < len;i++){
            if(this[i](name) !== &#39;next&#39;){
                break;
            }
        }    
    }
}
ログイン後にコピー

悪くはないのですが、このやり方では毎回手動で新しいSlinkを作成する必要があり、少々面倒なので、新しいSlinkの処理を にカプセル化します。 jQuery と同様の関数:

function Slink(){
    this.thens = [];
}
Slink.prototype = {
    add: function(f){
            if(typeof f === &#39;function&#39;){
                this.thens.push(f);
                return this;        
            }        
    },
    resolve: function(name){
            for(var i = 0, len = this.thens.length; i < len; i++){
                if(this.thens[i](name) !== &#39;next&#39;){
                    break;
                }
            }    
    }
}
ログイン後にコピー

テスト コードは次のとおりです:

var thens = new Slink();
thens.add(f1).add(f2).add(f3);
thens.resolve();
ログイン後にコピー

さて、これで完了です。次は構文上の糖衣問題です。 コードは次のように構成されています:

function $go(f){
    return new Slink(f);
}
function Slink(f){
    this.thens = [];
    this.thens.push(f);
}
Slink.prototype = {
    add: function(f){
            if(typeof f === &#39;function&#39;){
                this.thens.push(f);
                return this;        
            }        
    },
    resolve: function(name){
            for(var i = 0, len = this.thens.length; i < len; i++){
                if(this.thens[i](name) !== &#39;next&#39;){
                    break;
                }
            }    
    }
}
ログイン後にコピー

テスト コードは次のとおりです。

$go(f1).add(f2).add(f3).resolve();
ログイン後にコピー

もちろん、配列メソッドの使用を除いて、次のように

クロージャ

を使用してチェーンの平坦化効果を実現することもできます。

function _if(f){
    return new Slink(f);
}
function Slink(f){
    this.thens = [];
    this.thens.push(f);
}
Slink.prototype = {
    _elseIf: function(f){
            if(typeof f === &#39;function&#39;){
                this.thens.push(f);
                return this;        
            }        
    },
    _else: function(f){
            return this._elseIf(f);
    },
    resolve: function(name){
            for(var i = 0, len = this.thens.length; i < len; i++){
                if(this.thens[i](name) !== &#39;next&#39;){
                    break;
                }
            }
            return this;            
    }
}
ログイン後にコピー

テスト コードは次のとおりです:

_if(f1)._elseIf(f2)._else(f3).resolve();
ログイン後にコピー
ログイン後にコピー

3. 非同期コードチェーンのフラット化 上で説明したことはすべて同期プロセスですが、チェーン呼び出し関数に非同期状況がある場合はどうなるでしょうか?

どういう意味ですか?以下の通りです:

var func = Function.prototype;
func._else = func._elseIf = function(fn){
    var _this = this;
    return function(){
        var res = _this.apply(this,arguments);
        if(res==="next"){  //值为Boolean
            return fn.apply(this,arguments);
        }
        return res;
    }
}
ログイン後にコピー
setTimeoutを使用してf1を非同期にしました。上記のコードのロジックによれば、f1が完全に実行された(setTimeoutの実行を含む)後にf2を実行するかどうかを判断する必要がありますが、本当にそうなるのでしょうか?

テストコードは以下の通りです:

function f1(name){
    if(name === &#39;Monkey&#39;){
        console.log(&#39;yes, I am Monkey&#39;);
    }else{
        return &#39;next&#39;;
    }
}
function f2(name){
    if(name === &#39;Dorie&#39;){
        console.log(&#39;yes, I am Dorie&#39;);
    }else{
        return &#39;next&#39;;
    }
}
function f3(){
    console.log(&#39;sorry, over for ending!&#39;);
}
f1._elseIf(f2)._else(f3)('Dorie');
ログイン後にコピー

コードを実行した結果は何も出力されません。

なぜですか?

JavaScript はシングルスレッドであるためです。詳しくは(こちら)をご覧ください

それでは、どうやって解決すればいいのでしょうか?

非同期コードがあり、後続のチェーンは非同期コードの後に​​処理する必要があるため、次のように、非同期コードが実行されるのを待ってから後続のチェーンを実行します。これは Slink オブジェクトを表し、resolve メソッドが変更されています。確かに、Slink コンストラクターとプロトタイプ チェーンは次のように少し調整する必要があります:

function f1(name){
    setTimeout(function(){
        if(name === &#39;Monkey&#39;){
            console.log(&#39;yes, I am Monkey&#39;);
        }else{
            return &#39;next&#39;;
        }
    }, 2000);
}
function f2(name){
    if(name === &#39;Dorie&#39;){
        console.log(&#39;yes, I am Dorie&#39;);
    }else{
        return &#39;next&#39;;
    }
}
function f3(){
    console.log(&#39;sorry, over for ending!&#39;);
}
ログイン後にコピー
テスト コードは次のとおりです:

_if(f1)._elseIf(f2)._else(f3).resolve();
ログイン後にコピー
ログイン後にコピー

ははは。プロミスを知っていますが、毛織物は似たような感じですか?

はい、目的は同じで、非同期コードを平坦化するという目的を達成することですが、ここでのコードは Promise よりもはるかに単純です。 Promiseについて詳しくは(こちら)をご覧ください。

上記は JavaScript チェーン構造のシリアル化の詳細な説明です。その他の関連コンテンツについては、PHP 中国語 Web サイト (www.php.cn) に注目してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!