Maison > interface Web > js tutoriel > Explication détaillée du currying de la fonction JavaScript

Explication détaillée du currying de la fonction JavaScript

黄舟
Libérer: 2017-02-27 14:29:14
original
1560 Les gens l'ont consulté

Explication détaillée du currying de fonctions JavaScript

Explication du currying par l'Encyclopédie Baidu : En informatique, le currying est le processus d'acceptation Une technique qui transforme une fonction avec plusieurs paramètres dans une fonction qui accepte un seul paramètre (le premier paramètre de la fonction d'origine) et renvoie une nouvelle fonction qui accepte les paramètres restants et renvoie un résultat. Cette technique a été nommée par Christopher Strachey en l'honneur du logicien Haskell Curry, bien qu'elle ait été inventée par Moses Schnfinkel et Gottlob Frege.
Je crois que peu de gens peuvent immédiatement comprendre quelle est la fonction du curry après avoir lu l'explication ci-dessus. En termes simples, l'objectif principal du currying de fonctions est de réduire les paramètres de fonction et de privatiser certains paramètres fixes. Ce qui suit montre un code très simple pour calculer l'aire d'un cercle pour illustrer le principe du currying des fonctions :

//circle函数,接受半径r和πfunction circle(r,p){
    //计算半径为r的圆的面积
    var area=p*r*r;    return area;
}/*
 * 通过函数柯里化来简化circle函数,只传入半径就能计算出面积
 * 不管怎么样,π是不会变的,因此我们将他写死,不需要外部调用传入
 */function curryCircle(r){
    var p=3.14;    var area=p*r*r;    return area;
}
Copier après la connexion
Copier après la connexion

Vous penserez peut-être que ce code est bizarre, mais c'est le vrai visage de la fonction curry. Bien sûr, le code ci-dessus n'est qu'un très petit exemple. Le curry de fonctions dans le monde réel sera un peu plus vicieux. Discutons d'un exemple plus général ci-dessous. En supposant que π n'est pas unique (par exemple, nous avons trois types de π), π dans notre formule de calcul de l'aire du cercle changera selon différents scénarios. Pour le moment, nous ne pouvons pas l'écrire directement, mais devons configurer π. selon différents environnements :

//circle函数,接受半径r和π
function circle(r,p){
    //计算半径为r的圆的面积
    var area=p*r*r;    
    return area;
}
//针对circle函数的柯里化函数function curry(fn,p){
    var finalMethod=function(r){
        var result=fn(r,p);        return result;
    }    return finalMethod;
}
//我们有3种不同的πvar curryCircle1=curry(circle,1.14);
var curryCircle2=curry(circle,2.14);
var curryCircle3=curry(circle,3.14);
//输出:4.56  8.56  12.56
console.log(curryCircle1(2),curryCircle2(2),curryCircle3(2));
Copier après la connexion

Comme vous pouvez le voir, la méthode curry encapsule la méthode du cercle la plus basique, enregistre le paramètre p défini (π) et renvoie une méthode finalMethod, de sorte que lorsque nous appelons enfin finalMethod, il suffit de passer le paramètre r (rayon) pour pouvoir être complété. À l'aide de la fonction currying, nous disposons de trois méthodes simplifiées pour calculer l'aire d'un cercle. La fonction currying présentée ci-dessus ne peut être appliquée qu'au calcul de l'aire du cercle. Cette fois, nous écrivons une fonction de currying plus générale :

function curry(fn){
    //第一个参数是基础执行方法,slice切除
    var args=Array.prototype.slice.call(arguments,1);    //直接返回匿名函数
    return function(){
        //slice新参数以便能调用concat
        var innerArgs=Array.prototype.slice.call(arguments);        //将配置的参数和新传入的参数合并
        var finalArgs=args.concat(innerArgs);        return fn.apply(null,finalArgs);
    };
}
Copier après la connexion
Copier après la connexion

Le travail principal de la fonction curry() est de renvoyer la fonction. Les paramètres sont triés. Le premier paramètre de Curry() est la fonction à curry, et les autres paramètres sont les valeurs à transmettre. Afin d'obtenir tous les paramètres après le premier paramètre, la méthode slice() est appelée sur l'objet arguments et le paramètre 1 est passé pour indiquer que le tableau renvoyé contient tous les paramètres à partir du deuxième paramètre. Le tableau args contient alors les arguments de la fonction externe. Dans la fonction interne, le tableau innerArgs est créé pour stocker tous les paramètres entrants (slice() est à nouveau utilisé). Une fois que vous disposez des tableaux de paramètres qui stockent les fonctions externes et internes, vous pouvez utiliser la méthode concat() pour les fusionner dans finalArgs. Enfin, utilisez apply() pour transmettre le résultat à la fonction. On obtient ainsi une fonction générale de curry. S'il vous reste un peu d'énergie à ce stade, vous pouvez continuer la lecture. Nous présenterons la fonction curry utilisée dans jQuery.
Lors du curry d'une méthode, nous n'avons même pas besoin de passer fn pour dire au curry d'envelopper notre fonction. Nous pouvons directement lier la fonction et curry à travers le prototype :

Function.prototype.curry=function(){
    //利用原型的便利,我们可以直接通过this引用到方法
    var fn=this;    var args=Array.prototype.slice.call(arguments);    return function(){
        var arg=0;        //循环校验先前传入的参数和新传入的参数是否有差别
        for(var i=0;i<args.length && arg<arguments.length;i++){            if(args[i]===undefined){
                args[i]=arguments[arg++];
            }
        }        return fn.apply(this,args);
    };
};
Copier après la connexion
Copier après la connexion

Différent d'avant. , nous obtenons la référence de la méthode via cette référence, donc lorsque nous avons besoin de curry une fonction, il suffit d'écrire comme ceci :

var delay=setTimeout.curry(undefined,10);
Copier après la connexion
Copier après la connexion

delay est une fonction qui a été curry La fonction setTimeout définit un 10 retard d'une milliseconde à l'avance. Nous utilisons toujours args pour enregistrer la configuration des paramètres, mais cette fois il y a une différence : la différence entre args et arguments est vérifiée à l'intérieur de la boucle for, et sur la base de ce jugement, l'épissage des paramètres est terminé. Par conséquent, les paramètres transmis au curry doivent être des paramètres complets (ce qui signifie que des valeurs non définies doivent être transmises). Enfin nous avons implémenté une méthode de curry qui ne nécessite pas de passer en fn.

Explication détaillée du currying de fonctions JavaScript

Explication du currying par l'Encyclopédie Baidu : En informatique, le currying consiste à transformer une fonction qui accepte plusieurs paramètres en une fonction qui en accepte un. Une technique qui prend une fonction avec un seul paramètre (le premier paramètre de la fonction d'origine) et renvoie une nouvelle fonction qui accepte les paramètres restants et renvoie un résultat. Cette technique a été nommée par Christopher Strachey en l'honneur du logicien Haskell Curry, bien qu'elle ait été inventée par Moses Schnfinkel et Gottlob Frege.
Je crois que peu de gens peuvent immédiatement comprendre quelle est la fonction du curry après avoir lu l'explication ci-dessus. En termes simples, l'objectif principal du currying de fonctions est de réduire les paramètres de fonction et de privatiser certains paramètres fixes. Ce qui suit montre un code très simple pour calculer l'aire d'un cercle pour illustrer le principe du currying des fonctions :

//circle函数,接受半径r和πfunction circle(r,p){
    //计算半径为r的圆的面积
    var area=p*r*r;    return area;
}/*
 * 通过函数柯里化来简化circle函数,只传入半径就能计算出面积
 * 不管怎么样,π是不会变的,因此我们将他写死,不需要外部调用传入
 */function curryCircle(r){
    var p=3.14;    var area=p*r*r;    return area;
}
Copier après la connexion
Copier après la connexion

Vous penserez peut-être que ce code est bizarre, mais c'est le vrai visage de la fonction curry. Bien sûr, le code ci-dessus n'est qu'un très petit exemple. Le curry de fonctions dans le monde réel sera un peu plus vicieux. Discutons d'un exemple plus général ci-dessous. En supposant que π n'est pas unique (par exemple, nous avons trois types de π), π dans notre formule de calcul de l'aire du cercle changera selon différents scénarios. Pour le moment, nous ne pouvons pas l'écrire directement, mais devons configurer π. selon différents environnements :

//circle函数,接受半径r和πfunction circle(r,p){
    //计算半径为r的圆的面积
    var area=p*r*r;    return area;
}//针对circle函数的柯里化函数function curry(fn,p){
    var finalMethod=function(r){
        var result=fn(r,p);        return result;
    }    return finalMethod;
}
//我们有3种不同的π
var curryCircle1=curry(circle,1.14);
var curryCircle2=curry(circle,2.14);
var curryCircle3=curry(circle,3.14);
//输出:4.56  8.56  12.56
console.log(curryCircle1(2),curryCircle2(2),curryCircle3(2));
Copier après la connexion

可以看到,curry方法通过封装最基础的circle方法,同时保存设置好的p参数(π),并返回一个finalMethod方法,这样我们最终调用finalMethod时就只需要传入参数r(半径)就可以完成。借助函数柯里化,我们拥有了三个简化的计算圆面积方法。上面展示的函数柯里化只能适用于圆面积的计算,这次我们编写一个更通用的柯里化函数:

function curry(fn){
    //第一个参数是基础执行方法,slice切除
    var args=Array.prototype.slice.call(arguments,1);    //直接返回匿名函数
    return function(){
        //slice新参数以便能调用concat
        var innerArgs=Array.prototype.slice.call(arguments);        //将配置的参数和新传入的参数合并
        var finalArgs=args.concat(innerArgs);        return fn.apply(null,finalArgs);
    };
}
Copier après la connexion
Copier après la connexion

curry()函数的主要工作就是将被返回函数的参数进行排序。Curry()的第一个参数是要进行柯里化的函数,其他参数是要传入的值。为了获取第一个参数之后的所有参数,在arguments对象上调用了slice()方法,并传入参数1表示被返回的数组包含从第二个参数开始的所有参数。然后args数组包含了来自外部函数的参数。在内部函数中,创建了innerArgs数组用来存放所有传入的参数(又一次使用了slice())。有了存放来自外部函数和内部函数的参数数组后,就可以使用concat()方法将他们合并成finalArgs。最后使用apply()将结果传递给该函数。这样就实现了一个通用的函数柯里化。如果到这此还有余力的读者可以接着往下看,我们将要介绍jQuery中使用的函数柯里化。
在针对某个方法进行柯里化时,我们甚至不用传入fn来告诉柯里化来包装我们的函数,我们可以通过原型直接将函数和柯里化绑定:

Function.prototype.curry=function(){
    //利用原型的便利,我们可以直接通过this引用到方法
    var fn=this;    var args=Array.prototype.slice.call(arguments);    return function(){
        var arg=0;        //循环校验先前传入的参数和新传入的参数是否有差别
        for(var i=0;i<args.length && arg<arguments.length;i++){            if(args[i]===undefined){
                args[i]=arguments[arg++];
            }
        }        return fn.apply(this,args);
    };
};
Copier après la connexion
Copier après la connexion

与之前不同,我们通过this引用获取了方法引用,这样当我们需要将某个函数柯里化时,只要这样写就可以:

var delay=setTimeout.curry(undefined,10);
Copier après la connexion
Copier après la connexion

delay就是一个已经被提前设定了10毫秒延迟的setTimeout函数。我们仍然通过args来保存参数配置,不过这次有点区别:在for循环内部会校验args和arguments的区别,以此判断来完成参数拼接。所以传给curry的参数必须是完整参数(即意味着不传的值要传入undefined)。最终我们实现了一个不需要传入fn的柯里化方法。

 以上就是详解JavaScript函数柯里化 的内容,更多相关内容请关注PHP中文网(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