Maison > interface Web > js tutoriel > Explication détaillée de la rationalisation des fonctions en JavaScript

Explication détaillée de la rationalisation des fonctions en JavaScript

青灯夜游
Libérer: 2020-12-18 17:53:58
avant
6561 Les gens l'ont consulté

Explication détaillée de la rationalisation des fonctions en JavaScript

Recommandations associées : "Tutoriel vidéo Javascript"

J'ai accidentellement vu la Fonction Curry lorsque je lisais des blogs techniques dans la communauté récemment , et j'ai également demandé à écrire à la main pour curry la fonction js J'ai pensé, quelle chose avancée est le curry ? Vous n'en avez jamais entendu parler ?

Je me suis penché sur le problème, je l'ai étudié et j'ai fait un peu de tri.

Qu'est-ce que le curry fonctionnel ?

Qu'est-ce que le curry fonctionnel ? Voyons d'abord comment Wikipédia explique :

En informatique, Currying (anglais : Currying), également traduit par Currying ou Currying, consiste à transformer une fonction qui accepte plusieurs paramètres en une fonction qui en accepte un. une fonction avec un seul paramètre (le premier paramètre de la fonction d'origine) et renvoyant une nouvelle fonction qui accepte les paramètres restants et renvoie le résultat.

Cette technique a été nommée par Christopher Strachey d'après le logicien Haskell Gary, bien qu'elle ait été inventée par Moses Schönfinkel et Gottlob Frege.

Intuitivement, le currying indique que "si vous corrigez certains paramètres, vous obtiendrez une fonction qui accepte les paramètres restants". Donc pour la fonction y^x à deux variables, si y=2 est fixe, on obtient la fonction 2^x à une variable.

Le concept de Currying n'est en fait pas compliqué. En termes faciles à comprendre : ne transmettez qu'une partie des paramètres à la fonction pour l'appeler, et laissez-la renvoyer une fonction pour traiter le reste. paramètres.

Si l'explication du texte est encore un peu abstraite, nous utiliserons la fonction add pour réaliser une implémentation simple de la fonction curry.

// 普通的add函数
function add(x, y) {
    return x + y
}

// add函数柯里化后
var curryingAdd = function(x) {
  return function(y) {
    return x + y;
  };
};

// 函数复用
var increment = curryingAdd(1);
var addTen = curryingAdd(10);

increment(2);
// 3
addTen(2);
// 12
Copier après la connexion

En fait, les paramètres x et y de la fonction add sont transformés en une fonction qui reçoit d'abord x puis renvoie une fonction pour traiter le paramètre y. Maintenant, l'idée devrait être plus claire, c'est-à-dire appeler la fonction en ne transmettant qu'une partie des paramètres et la laisser renvoyer une fonction pour traiter les paramètres restants.

Pourquoi avons-nous besoin de curry des fonctions ?

Après avoir lu ce qui précède sur le curry de la fonction add, la question se pose : à quoi sert de dépenser autant d'efforts pour encapsuler une couche ?

1. Réutilisation des paramètres

En fait, le premier exemple de curry de la fonction add a déjà impliqué la réutilisation de fonction provoquée par le curry de fonction. implémentez rapidement la fonction d'incrémentation et la fonction addTen via le curry de la fonction add. Regardons un exemple :

// 正常正则验证字符串 reg.test(txt)

// 函数封装后
function check(reg, txt) {
    return reg.test(txt)
}

check(/\d+/g, 'test')       //false
check(/[a-z]+/g, 'test')    //true

// Currying后
function curryingCheck(reg) {
    return function(txt) {
        return reg.test(txt)
    }
}

var hasNumber = curryingCheck(/\d+/g)
var hasLetter = curryingCheck(/[a-z]+/g)

hasNumber('test1')      // true
hasNumber('testtest')   // false
hasLetter('21212')      // false
Copier après la connexion

L'exemple ci-dessus est une vérification régulière, appelez directement check. J'ai de nombreux endroits où je dois vérifier s'il y a des nombres, je dois en fait réutiliser le premier paramètre reg, afin que d'autres endroits puissent appeler directement hasNumber, hasLetter et d'autres fonctions afin que les paramètres puissent être réutilisés. appel.

2. Confirmez à l'avance
var on = function(element, event, handler) {
    if (document.addEventListener) {
        if (element && event && handler) {
            element.addEventListener(event, handler, false);
        }
    } else {
        if (element && event && handler) {
            element.attachEvent('on' + event, handler);
        }
    }
}

var on = (function() {
    if (document.addEventListener) {
        return function(element, event, handler) {
            if (element && event && handler) {
                element.addEventListener(event, handler, false);
            }
        };
    } else {
        return function(element, event, handler) {
            if (element && event && handler) {
                element.attachEvent('on' + event, handler);
            }
        };
    }
})();
Copier après la connexion

Il peut être plus facile de comprendre s'il est écrit d'une autre manière. Ce qui précède consiste à déterminer d'abord le paramètre isSupport

.
var on = function(isSupport, element, event, handler) {
    isSupport = isSupport || document.addEventListener;
    if (isSupport) {
        return element.addEventListener(event, handler, false);
    } else {
        return element.attachEvent('on' + event, handler);
    }
}
Copier après la connexion

Dans le processus de réalisation de projets, il est très courant d'encapsuler certaines opérations DOM. La première façon d'écrire ci-dessus est également relativement courante, mais jetons un coup d'œil à la deuxième façon d'écrire. la première façon d'écrire est de s'auto-exécuter puis de renvoyer un La nouvelle fonction détermine en fait quelle méthode sera utilisée à l'avance, pour éviter de porter des jugements à chaque fois .

3. Calcul/opération retardé
Function.prototype.bind = function (context) {
    var _this = this
    var args = Array.prototype.slice.call(arguments, 1)

    return function() {
        return _this.apply(context, args)
    }
}
Copier après la connexion

Comme la liaison qui est souvent utilisée dans notre js, le mécanisme d'implémentation est le Currying.

Comment implémenter fonction Ke Lihua ?

Méthode d'encapsulation générale :

// 初步封装
var currying = function(fn) {
    // args 获取第一个方法内的全部参数
    var args = Array.prototype.slice.call(arguments, 1)
    return function() {
        // 将后面方法里的全部参数和args进行合并
        var newArgs = args.concat(Array.prototype.slice.call(arguments))
        // 把合并后的参数通过apply作为fn的参数并执行
        return fn.apply(this, newArgs)
    }
}
Copier après la connexion

Voici d'abord l'encapsulation préliminaire, en enregistrant les paramètres préliminaires par fermeture, puis en les épissant en obtenant les arguments restants, et enfin en exécutant la fonction de curry requise.

Cependant, la fonction ci-dessus présente encore quelques défauts si elle est renvoyée de cette manière, elle ne peut développer qu'un paramètre supplémentaire. Currying(a)(b)(c) ne semble pas être pris en charge (multi. -les appels de paramètres ne sont pas pris en charge), généralement dans ce cas, vous penserez à utiliser la récursivité et à l'encapsuler une couche plus loin.

// 支持多参数传递
function progressCurrying(fn, args) {

    var _this = this
    var len = fn.length;
    var args = args || [];

    return function() {
        var _args = Array.prototype.slice.call(arguments);
        Array.prototype.push.apply(args, _args);

        // 如果参数个数小于最初的fn.length,则递归调用,继续收集参数
        if (_args.length < len) {
            return progressCurrying.call(_this, fn, _args);
        }

        // 参数收集完毕,则执行fn
        return fn.apply(this, _args);
    }
}
Copier après la connexion

Ceci est en fait basé sur l'ajout d'appels récursifs préliminaires. Tant que le nombre de paramètres est inférieur à la longueur fn.initiale, la récursion continuera à être exécutée.

Comment se déroule la performance du curry fonctionnel ?

Concernant les performances de Currying, il faut connaître les points suivants :

  • L'accès aux objets arguments est généralement un peu plus lent que l'accès aux paramètres nommés
  • Certaines versions plus anciennes l'implémentation de arguments.length dans les navigateurs est assez lente
  • L'utilisation de fn.apply(…) et fn.call(…) est généralement légèrement plus lente que l'appel direct de fn(…)
  • Créer un grand le nombre de portées imbriquées et de fonctions de fermeture entraînera des coûts, à la fois en termes de mémoire et de vitesse

En fait, dans la plupart des applications, le principal goulot d'étranglement des performances est l'exploitation des nœuds DOM, la perte de performances de ce js est fondamentalement négligeable, le curry peut donc être utilisé directement et en toute sécurité.

Questions d'entretien au curry

// 实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;

function add() {
    // 第一次执行时,定义一个数组专门用来存储所有的参数
    var _args = Array.prototype.slice.call(arguments);

    // 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
    var _adder = function() {
        _args.push(…arguments);
        return _adder;
    };

    // 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
    _adder.toString = function () {
        return _args.reduce(function (a, b) {
            return a + b;
        });
    }
    return _adder;
}

add(1)(2)(3)                // 6
add(1, 2, 3)(4)             // 10
add(1)(2)(3)(4)(5)          // 15
add(2, 6)(1)                // 9
Copier après la connexion

Résumé

En passant simplement quelques paramètres, vous pouvez créer dynamiquement de nouvelles fonctions utiles et cela apporte également un avantage supplémentaire, c'est-à-dire le ; la définition de la fonction mathématique est conservée, bien qu'il y ait plus d'un paramètre.

La fonction Currying est très simple d'utilisation, et l'utiliser au quotidien est pour moi tout simplement un plaisir. C’est un outil essentiel à avoir sous la main pour rendre la programmation fonctionnelle moins lourde et ennuyeuse.

Pour plus de connaissances sur la programmation, veuillez visiter : Introduction à la programmation ! !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:segmentfault.com
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