Comment démarrer rapidement avec VUE3.0 : Entrez
les recommandations liées à l'apprentissage : Tutoriel d'apprentissage JavaScript
J'ai vu de nombreuses explications sur la programmation fonctionnelle, mais la plupart d'entre elles sont au niveau théorique, et certaines concernent uniquement les langages de programmation fonctionnels purs comme Haskell. Le but de cet article est de parler de la pratique spécifique de la programmation fonctionnelle en JavaScript à mes yeux. La raison pour laquelle elle est « à mes yeux » signifie que ce que je dis ne représente que mon opinion personnelle, qui peut entrer en conflit avec certains concepts stricts.
Cet article omettra de nombreuses introductions formelles de concepts et se concentrera sur la démonstration de ce qu'est le code fonctionnel en JavaScript, quelle est la différence entre le code fonctionnel et l'écriture générale, quels avantages le code fonctionnel peut nous apporter et quels sont les modèles fonctionnels communs ?
Je pense que la programmation fonctionnelle peut être comprise comme une méthode de programmation qui utilise des fonctions comme support principal. L'utilisation de fonctions pour désassembler et résumer des expressions générales
est comparée aux impératifs. Les principaux points sont les suivants :
une sémantique plus claire, une réutilisabilité plus élevée, une maintenabilité plus élevée, une meilleure limitation de la portée et moins d'effets secondaires. Programmation fonctionnelle de base. L'exemple suivant est une expression fonctionnelle spécifique du
code Javascript
// chaque mot du tableau. première lettre // Écriture générale const arr = ['apple', 'pen', 'apple-pen'] for(const i in arr){; const c = arr[i][0]; arr[i] = c.toUpperCase() + arr[i].slice(1 }); console.log(arr); // Méthode d'écriture fonctionnelle - function upperFirst(word) { return word[0].toUpperCase() + word.slice(1 }); fonction motVersUpperCase(arr) { return arr.map(upperFirst } console.log(wordToUpperCase(['apple', 'pen', 'apple-pen'])); // Méthode d'écriture fonctionnelle 2 console.log(arr.map(['apple', 'pen', 'apple-pen'], word => word[0].toUpperCase() + word.slice(1))) ;
Lorsque la situation devient plus complexe, la manière d'écrire les expressions rencontrera plusieurs problèmes :
le sens n'est pas évident, il devient progressivement difficile à maintenir, la réutilisabilité est mauvaise, plus de code sera généré et de nombreuses variables intermédiaires seront générées. La programmation fonctionnelle résout bien les problèmes ci-dessus. Tout d'abord, reportez-vous à la méthode d'écriture fonctionnelle 1, qui utilise l'encapsulation de fonctions pour décomposer les fonctions (la granularité n'est pas unique), les encapsule dans différentes fonctions, puis utilise des appels combinés pour atteindre l'objectif. Cela rend l’expression claire et facile à maintenir, à réutiliser et à étendre. Deuxièmement, en utilisant des fonctions d'ordre supérieur, Array.map remplace for...of pour le parcours de tableau, réduisant ainsi les variables et opérations intermédiaires.
La principale différence entre la méthode d'écriture fonctionnelle 1 et la méthode d'écriture fonctionnelle 2 est que vous pouvez déterminer si la fonction peut être réutilisée plus tard. Sinon, cette dernière est meilleure.
À partir de la méthode d'écriture fonctionnelle 2 ci-dessus, nous pouvons voir que dans le processus d'écriture du code fonctionnel, il est facile de provoquer une extension horizontale, c'est-à-dire de produire plusieurs couches d'imbrication. Donnons un exemple extrême ci-dessous.
Code Javascript
// Calculer la somme des nombres // Méthode d'écriture générale console.log(1 + 2 + 3 - 4) // Fonction d'écriture fonctionnelle sum(a, b) { renvoyer a + b ; fonction sous (a, b) { renvoyer un - b ; console.log(sub(sum(sum(1, 2), 3), 4); Cet exemple ne montre qu'un cas extrême d'extension horizontale. À mesure que le nombre de niveaux de fonctions imbriqués continue d'augmenter, le code deviendra moins lisible Les performances sont considérablement réduites et il est facile de commettre des erreurs. Dans ce cas, nous pouvons envisager plusieurs méthodes d’optimisation, comme l’optimisation en chaîne suivante. // Optimiser l'écriture (enfin, vous avez bien lu, c'est l'écriture en chaîne de lodash) Code Javascript const utils = { chaîne(a) { this._temp = a; rends ceci ; }, somme(b) { this._temp += b; rends ceci ; }, sous(b) { this._temp -= b; rends ceci ; }, valeur() { const _temp = this._temp; this._temp = non défini ; retourner _temp ; } } ; console.log(utils.chain(1).sum(2).sum(3).sub(4).value());
Après réécriture de cette manière, la structure globale deviendra plus claire et chaque maillon de la chaîne sera Que faire peut également être affiché facilement. Un autre bon exemple de comparaison entre l'imbrication de fonctions et le chaînage est la fonction de rappel et le modèle Promise.
Code Javascript
// Demander deux interfaces séquentiellement // Fonction de rappel import $ from 'jquery' $.post('a/url/to/target', (rs) => { si(rs){ $.post('a/url/vers/une autre/cible', (rs2) => { si(rs2){ $.post('a/url/to/third/target'); } }); } }); // Requête d'importation de promesse depuis 'catta' ; // catta est un outil de requête léger qui prend en charge fetch, jsonp, ajax et n'a aucune dépendance request('a/url/to/target') .then(rs => rs ? $.post('a/url/to/another/target') : Promise.reject()) .then(rs2 => rs2 ? $.post('a/url/to/third/target') : Promise.reject());
À mesure que le niveau d'imbrication de la fonction de rappel et la complexité à un seul niveau augmentent, il deviendra C'est gonflée et difficile à maintenir, mais la structure en chaîne de Promise peut encore s'étendre verticalement lorsque la complexité est élevée, et l'isolement hiérarchique est très clair.
La fermeture du modèle de programmation fonctionnelle commune
peut conserver des variables locales dans un bloc de code qui n'est pas publié.C'est ce qu'on appelle une fermeture.
Le concept de fermeture est relativement abstrait.Je pense que tout le monde connaît et utilise cette fonctionnalité
. les sacs peuvent-ils nous apporter ?
Voyons d'abord comment créer une fermeture :
Code Javascript
// Créer une fonction de fermeture makeCounter() { soit k = 0 ; fonction de retour() { renvoie ++k ; }; } const compteur = makeCounter(); console.log(counter()); // 1 console.log(counter()); // 2
makeCounter Le bloc de code de cette fonction fait référence à la variable locale k dans la fonction renvoyée, provoquant l'échec de la variable locale. la fonction est exécutée, elle est recyclée par le système, générant ainsi une fermeture. La fonction de cette fermeture est de « conserver » la variable locale afin que la variable puisse être réutilisée lorsque la fonction interne est appelée ; contrairement aux variables globales, cette variable ne peut être référencée qu'à l'intérieur de la fonction ;
En d’autres termes, les fermetures créent en fait des « variables persistantes » qui sont propres à la fonction.
Ainsi, à partir de cet exemple, nous pouvons conclure que les conditions pour créer une fermeture sont :
il existe des fonctions internes et externes. La fonction interne fait référence aux variables locales de la fonction externe. Le but principal de la fermeture est de définir. certaines fonctions. Variables persistantes limitées au domaine, ces variables peuvent être utilisées pour la mise en cache ou les calculs intermédiaires, etc.
Code Javascript
// Outil de mise en cache simple // La fonction anonyme crée une fermeture const cache = (function() { const magasin = {}; retour { obtenir (clé) { return store[clé] ; }, set(clé, val) { magasin[clé] = val; } } }()); cache.set('a', 1); cache.get('a'); // 1L'exemple
ci-dessus est l'implémentation d'un simple outil de mise en cache. La fonction anonyme crée une fermeture afin que l'objet du magasin puisse toujours être référencé. , ne sera pas recyclé.
Inconvénients des fermetures : les variables persistantes ne seront pas libérées normalement et continueront à occuper de l'espace mémoire, ce qui peut facilement entraîner un gaspillage de mémoire, donc certains mécanismes de nettoyage manuel supplémentaires sont généralement nécessaires.
fonction qui accepte ou renvoie une fonction est appelée fonction d'ordre supérieur.
Cela semble être un mot très froid, mais en fait, nous l'utilisons souvent, mais nous ne connaissons tout simplement pas leurs noms. Le langage JavaScript prend en charge nativement les fonctions d'ordre supérieur, car les fonctions JavaScript sont des citoyens de première classe et peuvent être utilisées à la fois comme paramètres et comme valeur de retour d'une autre fonction.
Nous pouvons souvent voir de nombreuses fonctions natives d'ordre élevé en JavaScript, telles que Array.map, Array.reduce et Array.filter.
Prenons map comme exemple. Voyons comment il utilise
map (le mappageest une collection de
En d'autres termes, chaque élément de l'ensemble est soumis à la même transformation pour générer une nouvelle
carte d'ensemble. En tant que fonction d'ordre supérieur, elle accepte un paramètre de fonction comme
code Javascript
logique du mappage// Ajoutez-en un à chaque élément de. le tableau pour former Un nouveau tableau // Méthode d'écriture générale const arr = [1,2,3]; const rs = [] for(const n of arr){ rs.push(++n); } console.log(rs) // map réécrit const arr = [1,2,3]; const rs = arr.map(n => ++n);
la méthode d'écriture générale ci-dessus, l'utilisation de la boucle for...of pour parcourir le tableau entraînera opérations supplémentaires, et Il y a un risque de changer le tableau d'origine
, mais la fonction map encapsule les opérations nécessaires, de sorte que nous n'avons qu'à nous soucier de l'implémentation fonctionnelle de la logique de mappage, ce qui réduit la quantité de code et le risque de côté effets.
donne certains paramètres d'une fonction et génère une nouvelle fonction qui accepte d'autres paramètres.
Vous n'entendrez peut-être pas souvent ce terme, mais quiconque a utilisé undescore ou lodash l'a vu.
Il existe une fonction magique _.partial, qui est
du code Javascript
curry// Obtenez le chemin relatif du fichier cible vers le chemin de base // La méthode d'écriture générale est const BASE = '/path/to/base'; chemin. relatif(BASE, '/some/path'); // _.parical réécriture const BASE = '/path/to/base'; const relativeFromBase = _.partial(path.relative, BASE); const relativePath = relativeFromBase('/some/path');
Grâce à _.partial, nous obtenons la nouvelle fonction relativeFromBase. Lorsque cette fonction est appelée, cela équivaut à appeler path.relative, et le premier paramètre est passé à BASE par défaut. . Les paramètres suivants transmis sont ajoutés dans l’ordre.
Dans ce cas, ce que nous voulons vraiment accomplir, c'est obtenir le chemin relatif à BASE à chaque fois, et non relatif à un chemin quelconque. Le curry nous permet de nous soucier uniquement de certains paramètres d'une fonction, ce qui rend le but de la fonction plus clair et son appel plus simple.
combine les capacités de plusieurs fonctions pour créer une nouvelle fonction.
Vous l'avez peut-être vu pour la première fois dans lodash, la méthode compose (maintenant appelée flow)
Code Javascript
// Mettez en majuscule chaque mot du tableau, faites Base64. //Méthode d'écriture générale (l'une d'elles) const arr = ['pen', 'apple', 'applypen']; const rs = []; rs.push(btoa(w.toUpperCase())); } console.log(rs); // _.flow réécriture const arr = ['pen', 'apple', 'applypen']; const upperAndBase64 = _.partialRight(_.map, _.flow(_.upperCase, btoa)); console.log(upperAndBase64(arr));
_.flow fusionne les capacités des fonctions de conversion en majuscules et de conversion Base64 pour générer une nouvelle fonction. Pratique à utiliser comme fonction de paramètre ou à réutiliser ultérieurement.
De mon point de vue, ma compréhension de la programmation fonctionnelle JavaScript peut être différente de nombreux concepts traditionnels. Je ne pense pas seulement que les fonctions d'ordre supérieur comptent comme programmation fonctionnelle. D'autres, comme les appels combinés de fonctions ordinaires, les structures de chaîne, etc., appartiennent, je pense, à la catégorie de la programmation fonctionnelle, à condition qu'elles utilisent des fonctions comme fonctions principales. transporteur.
Et je pense que la programmation fonctionnelle n’est pas nécessaire et ne devrait pas non plus être une règle ou une exigence obligatoire. Comme les idées orientées objet ou autres, c'est aussi l'une des voies. Dans la plupart des cas, nous devrions être une combinaison de plusieurs concepts plutôt que de nous limiter à ces concepts.
Recommandations associées : Tutoriel JavaScript
Ce qui précède est une discussion détaillée de la programmation fonctionnelle JavaScript. Pour plus d'informations, veuillez prêter attention aux autres articles connexes sur le site Web PHP chinois !