Maison > interface Web > js tutoriel > Explication détaillée de la sérialisation de la structure de la chaîne JavaScript

Explication détaillée de la sérialisation de la structure de la chaîne JavaScript

黄舟
Libérer: 2017-03-04 15:21:22
original
1165 Les gens l'ont consulté

1. Présentation

En JavaScript, il y a trop de codes de modèles de chaîne, comme suit :

if_else :

if(...){
    //TODO
}else if(...){
    //TODO
}else{
    //TODO
}
Copier après la connexion

interrupteur :

switch(name){
    case ...:{
        //TODO
        break;
    }
    case ...:{
        //TODO
        break;
    }
    default:{
        //TODO    
    }
}
Copier après la connexion

Question : Comme le code de chaîne ci-dessus, si on veut l'aplatir et l'enchaîner Tissu de laine ? Comme suit :

//fn1,f2,f3为处理函数
_if(fn1)._elseIf(fn2)._else(fn3);
Copier après la connexion
Copier après la connexion

Essayons de le mettre en œuvre ensemble.

2. Aplatissement du code de chaîne

Supposons maintenant que nous ayons le code de chaîne suivant :

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!');
}
Copier après la connexion

D'accord, maintenant nous allons l'aplatir étape par étape" Plat".

En fait, en regardant le code ci-dessus, il n'est pas difficile de constater que le format if...else est en fait une liste à lien unique dans la structure de données. Ensuite, utilisez initialement JavaScript pour implémenter une liste à lien unique. liste, comme suit :

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);
Copier après la connexion

Parmi eux, f1, f2 et f3 sont des fonctions de jugement, et nous supposons que si f1, f2 et f3 renvoient « suivant », nous continuerons à chercher vers le bas, sinon, nous arrêterons de chercher vers le bas. Comme suit :

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;);
}
Copier après la connexion

D'accord, c'est le modèle de la liste chaînée.

Cependant, notre objectif ultime est d'atteindre ce qui suit ?

//fn1,f2,f3为处理函数
_if(fn1)._elseIf(fn2)._else(fn3);
Copier après la connexion
Copier après la connexion

Vous pourriez dire, ne serait-il pas bien de changer le code ci-dessus par le suivant ? ! !

thens.push(f1).push(f2).push(f3).resolve();
Copier après la connexion

Mais, La méthode push de JavaScript renvoie la nouvelle longueur du tableau, pas l'objet tableau.

Donc, alors nous ne pouvons écrire qu'une nouvelle méthode add, qui a le même effet que push, mais renvoie un objet tableau. Comme suit :

thens.add = function(f){
    if(typeof f === &#39;function&#39;){
        this.push(f);
        return this;        
    }        
}
Copier après la connexion

Le code de test est le suivant :

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();
Copier après la connexion

Cependant, cela présente un inconvénient. Nous lions les méthodes d'ajout et de résolution aux méthodes d'ajout et de résolution. variable globale thens Vous ne pouvez pas simplement copier et coller la méthode à chaque fois que vous créez un tableau, donc le code refactorisé est le suivant :

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;
            }
        }    
    }
}
Copier après la connexion

Évidemment, les méthodes publiques comme add et solve seront utilisées à chaque fois c'est instancié. , il n'est pas scientifique de tous les créer, alors utilisez le prototype pour continuer à déformer sur la base d'origine, comme suit :

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;
                }
            }    
    }
}
Copier après la connexion

Le code de test est le suivant :

var thens = new Slink();
thens.add(f1).add(f2).add(f3);
thens.resolve();
Copier après la connexion

Oui, mais dans ce cas, nous devons créer manuellement un nouveau Slink à chaque fois, ce qui est un peu gênant. Par conséquent, nous encapsulons le nouveau processus Slink dans une fonction, tout comme jQuery, comme. suit :

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;
                }
            }    
    }
}
Copier après la connexion

Le code du test est le suivant :

$go(f1).add(f2).add(f3).resolve();
Copier après la connexion

D'accord, vous avez terminé, vient maintenant le problème du sucre grammatical. Le code est. organisé comme suit :

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;            
    }
}
Copier après la connexion

Le code du test est le suivant :

_if(f1)._elseIf(f2)._else(f3).resolve();
Copier après la connexion
Copier après la connexion

Bien sûr, en plus d'utiliser des tableaux, vous pouvez également utiliser fermetures pour obtenir un effet d'aplatissement de la chaîne, comme suit :

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;
    }
}
Copier après la connexion

Le code de test est le suivant :

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');
Copier après la connexion

3. chaîne de code asynchrone

Ce dont nous avons discuté ci-dessus sont tous des processus synchrones. Si, les appels en chaîne Y a-t-il une situation asynchrone dans la fonction ?

Qu'est-ce que cela signifie ? Comme suit :

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;);
}
Copier après la connexion

Nous avons rendu f1 asynchrone en utilisant setTimeout. Selon la logique du code ci-dessus, nous devrions attendre que f1 soit complètement exécuté (y compris l'exécution de setTimeout) avant de juger s'il faut exécuter f2, mais c'est vraiment le cas ?

Le code de test est le suivant :

_if(f1)._elseIf(f2)._else(f3).resolve();
Copier après la connexion
Copier après la connexion

Le résultat de l'exécution du code est que rien n'est sorti.

Pourquoi ?

Parce que JavaScript est monothread. Voir (ici) pour plus de détails

Alors comment le résoudre ?

Puisqu'il y a du code asynchrone et que la chaîne suivante doit être traitée après le code asynchrone, alors nous attendons que le code asynchrone soit terminé avant d'exécuter la chaîne suivante, comme suit :

function f1(name){
    setTimeout(function(){
        if(name === &#39;Monkey&#39;){
            console.log(&#39;yes, I am Monkey&#39;);
        }else{
            //处理后续链
            this.resolve(name, 1);//1代表下一个需处理函数在数组中的位置
        }
    }.bind(this), 2000);
}
Copier après la connexion

Eh bien, puisque dans la fonction, nous avons utilisé ceci, qui représente l'objet Slink, et modifié la méthode de résolution, nous devons affiner le constructeur Slink et la chaîne de prototypes, comme suit :

function Slink(f){
    this.thens = [];
    this.thens.push(f.bind(this));
}
Slink.prototype = {
    _elseIf: function(f){
            if(typeof f === &#39;function&#39;){
                this.thens.push(f.bind(this));
                return this;        
            }        
    },
    _else: function(f){
            return this._elseIf(f.bind(this));
    },
    resolve: function(name, flag){
            for(var i = flag, len = this.thens.length; i < len; i++){
                if(this.thens[i](name) !== &#39;next&#39;){
                    break;
                }
            }
            return this;            
    }
}
Copier après la connexion

Le test le code est le suivant :

function f1(name){
    setTimeout(function(){
        if(name === &#39;Monkey&#39;){
            console.log(&#39;yes, I am Monkey&#39;);
        }else{
            //处理后续链
            this.resolve(name, 1);//1代表下一个需处理函数在数组中的位置
        }
    }.bind(this), 2000);
}
function f2(name){
    if(name === 'Dorie'){
        console.log('yes, I am Dorie');
    }else{
        return 'next';
    }
}
function f3(){
    console.log('sorry, over for ending!');
}
_if(f1)._elseIf(f2)._else(f3).resolve('',0);
Copier après la connexion

Haha, si tu connais Promise, tu penses que c'est si similaire ?

Oui, le but est le même, atteindre l'objectif d'aplatir le code asynchrone, mais le code ici est beaucoup plus simple que Promise. Pour plus de détails sur Promise, voir (ici).

Ce qui précède est l'explication détaillée de la sérialisation de la structure de la chaîne JavaScript. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php.cn) !


Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal