ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScriptチェーン構造のシリアル化の詳細説明

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

黄舟
黄舟オリジナル
2017-03-04 15:21:221136ブラウズ

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) に注目してください。

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