Vous avez peut-être entendu parler de fonctions récursives en JavaScript, et même essayé d'en écrire. Mais vous n'avez peut-être pas vu de nombreux exemples de récursivité qui fonctionne réellement. En fait, outre la particularité de cette approche, vous n'avez peut-être pas considéré quand et où la récursivité est utile, ou à quel point elle est dangereuse si elle est utilisée mal.
Points clés
- Recursion est une méthode JavaScript qui permet à la fonction de s'appeler à plusieurs reprises jusqu'à ce que le résultat soit atteint. Il est particulièrement utile pour les problèmes impliquant des branches itératives, telles que les mathématiques fractales, le tri ou la traversée des structures de données complexes ou non linéaires.
- Bien que la récursivité puisse rendre le code plus concis et plus facile à comprendre, s'il est utilisé mal, il peut être dangereux en raison du risque de dépasser la capacité de mémoire du moteur. En effet, les fonctions récursives JavaScript doivent garder une trace d'où elles sont appelées à chaque fois afin qu'ils puissent continuer à s'exécuter au bon endroit.
- Dans de nombreux langages de programmation fonctionnelle, une technique appelée optimisation des appels de queue est utilisée pour gérer la récursivité. Cela permet à chaque boucle continue de la fonction récursive de se produire immédiatement, plut?t que de l'empilement en mémoire. Cependant, la plupart des compilateurs JavaScript ne sont pas encore optimisés pour cela.
- Les fonctions de rebond personnalisées peuvent être construites pour gérer itérativement l'exécution récursive, ne laissant qu'une seule opération sur la pile à la fois. Cela peut aider à éviter de créer des opérations de pile profonde en attendant d'être effectuées, mais généralement au détriment des performances et de la lisibilité.
Objectif de la récursivité
La récursivité est une technique qui itère à travers l'opération en ayant une fonction s'appeler à plusieurs reprises jusqu'à ce que le résultat soit obtenu. La plupart des boucles peuvent être réécrites dans des styles récursifs, et dans certains langages de programmation fonctionnelle, cette méthode de boucle est la valeur par défaut.
Cependant, bien que le style de programmation fonctionnelle de JavaScript prend en charge les fonctions récursives, nous devons réaliser que la plupart des compilateurs JavaScript ne sont pas actuellement optimisés en toute sécurité pour eux.
La récursivité est mieux utilisée lorsque vous devez appeler à plusieurs reprises la même fonction avec différents paramètres dans la boucle. Bien qu'il puisse être utilisé dans de nombreux cas, il est plus efficace pour résoudre des problèmes impliquant des branches itératives telles que les mathématiques fractales, le tri ou la traversée des n?uds de structures de données complexes ou non linéaires.
L'une des raisons pour lesquelles la récursivité est privilégiée dans les langages de programmation fonctionnelle est qu'il permet un code de construction qui ne nécessite pas l'utilisation de variables locales pour définir et maintenir l'état. Les fonctions récursives sont également faciles à tester car elles sont faciles à écrire de manière pure, ont une valeur de retour spécifique et cohérente pour une entrée donnée et n'ont aucun effet secondaire sur l'état de la variable externe.
cycle
Un exemple de fonction classique que la récursivité peut être appliquée est factorielle. Il s'agit d'une fonction qui renvoie le résultat d'un nombre multiplié à plusieurs reprises par chaque entier précédent, jusqu'à 1.
Par exemple, le factoriel de 3 est:
<code>3 × 2 × 1 = 6</code>Le factoriel de
6 est:
<code>3 × 2 × 1 = 6</code>
Vous pouvez voir à quelle vitesse ces résultats augmentent. Vous pouvez également nous voir répéter le même comportement encore et encore. Nous prenons le résultat d'une opération de multiplication et le multiplions par la deuxième valeur à moins 1. Ensuite, nous le faisons encore et encore jusqu'à ce que nous atteignions 1.
En utilisant une boucle pour une boucle, il n'est pas difficile de créer une fonction qui itère pour le faire jusqu'à ce que le bon résultat soit renvoyé:
<code>6 × 5 × 4 × 3 × 2 × 1 = 720</code>
Cela fonctionne, mais du point de vue de la programmation fonctionnelle, il n'est pas élégant. Pour prendre en charge la boucle FOR, puis renvoyer le résultat, nous devons utiliser plusieurs variables locales qui maintiennent et suivent l'état. Ne serait-il pas plus concis si nous pouvions jeter la boucle pour et adopter une méthode JavaScript plus fonctionnelle?
Recursion
Nous savons que JavaScript nous permet d'écrire des fonctions qui prennent des fonctions comme des paramètres. Et si nous voulons utiliser la fonction réelle que nous écrivons et l'exécutons dans le contexte où nous l'exécutons?
Est-ce même possible? bien s?r! Par exemple, considérez une boucle aussi simple:
var factor = function(number) { var result = 1; var count; for (count = number; count > 1; count--) { result *= count; } return result; }; console.log(factor(6)); // 720
Une fois cela fait, la valeur du compteur a changé, mais la boucle a terminé son travail d'impression de chaque valeur, car nous en avons lentement extrait l'état.
Les versions récursives de la même boucle peuvent ressembler davantage à ceci:
var counter = 10; while(counter > 0) { console.log(counter--); }
Avez-vous vu comment nous appelons la fonction de compte à rebours directement dans la définition de la fonction à rebours? JavaScript le gère comme un boss et fait seulement ce que vous voulez qu'il fasse. Chaque fois que le compte à rebours est exécuté, JavaScript suit où il est appelé, puis remonte à la pile de cet appel de fonction jusqu'à ce qu'il soit terminé. Notre fonction évite également la modification de l'état de toute variable, mais utilise toujours les valeurs passées pour contr?ler la récursivité.
Retour à notre cas factoriel, nous pouvons réécrire la fonction précédente comme celle-ci pour utiliser la récursivité:
var countdown = function(value) { if (value > 0) { console.log(value); return countdown(value - 1); } else { return value; } }; countdown(10);
L'écriture de code de cette manière nous permet de décrire l'intégralité du processus de manière apatride sans aucun effet secondaire. Il convient également de noter que nous testons d'abord les valeurs des paramètres transmises à la fonction, puis effectuons des calculs. Nous voulons toute fonction qui est sur le point de s'appeler pour sortir rapidement et proprement lorsqu'elle atteint sa terminaison. Pour les factoriels calculés de cette manière, lorsque le nombre entrant est nul ou négatif, la situation de terminaison est atteinte (nous pouvons également tester des valeurs négatives et renvoyer différents messages si nous le souhaitons).
Optimisation des appels de queue
L'un des problèmes des implémentations contemporaines JavaScript est qu'ils n'ont pas de moyen standard d'empêcher les fonctions récursives de s'accumuler infiniment et de consommer de la mémoire jusqu'à ce qu'ils dépassent la capacité du moteur. Les fonctions récursives JavaScript doivent garder une trace d'où elles sont appelées à chaque fois afin qu'ils puissent continuer à s'exécuter au bon endroit.
Dans de nombreux langages de programmation fonctionnelle tels que Haskell et Scheme, il est géré à l'aide d'une technique appelée optimisation des appels de queue. En utilisant l'optimisation des appels de queue, chaque boucle continue dans la fonction récursive se produira immédiatement, plut?t que de l'empilement en mémoire.
En théorie, l'optimisation des appels de queue fait partie de la norme ECMAScript 6 (la prochaine version de JavaScript actuelle), mais la plupart des plateformes ne l'ont pas encore entièrement implémentée.
Fonction de rebond
Si nécessaire, il existe des moyens de forcer JavaScript à exécuter des fonctions récursives de manière s?re. Par exemple, des fonctions de rebond personnalisées peuvent être con?ues pour gérer itérativement l'exécution récursive, ne laissant qu'une seule opération sur la pile à la fois. La fonction de rebond utilisée de cette manière peut profiter de la capacité de JavaScript à lier les fonctions à un contexte spécifique afin de rebondir la fonction récursive à elle-même, en construisant le résultat un à la fois jusqu'à ce que la boucle soit terminée. Cela évitera de créer des opérations de pile profonde en attendant l'exécution.
En fait, l'utilisation d'une fonction de rebond réduit souvent les performances pour la sécurité. De plus, la plupart de l'élégance et de la lisibilité que nous obtenons en écrivant des fonctions récursivement est perdue dans la convolution du code nécessaire pour que cette approche fonctionne en JavaScript.
Si vous êtes curieux, je vous encourage à en savoir plus sur ce concept et à partager vos pensées dans la discussion ci-dessous. Vous pouvez commencer par un court sujet sur Stackoverflow et explorer certains articles de Don Taylor et Mark McDonnell qui approfondissent les avantages et les inconvénients des fonctions de rebond en JavaScript.
Nous ne sommes pas encore à ce moment-là
La récursivité est une technique puissante qui mérite d'être connue. Dans de nombreux cas, la récursivité est le moyen le plus simple de résoudre des problèmes complexes. Cependant, avant que Ecmascript 6 ne s'implémente entièrement avec l'optimisation des appels de queue où nous en avons besoin, nous devons faire très attention à la fa?on et à la fa?on dont le récursif est appliqué.
FAQ sur la récursivité dans JavaScript fonctionnel (FAQ)
Quelle est la situation de base dans la récursivité? Pourquoi est-ce important?
La situation de base dans la récursivité est la condition qui empêche la fonction de s'appeler infiniment. Il est crucial car sans lui, la fonction récursive s'appellera infiniment, provoquant une erreur de débordement de pile. La situation de base est généralement la condition qu'une fonction vérifie avant de passer un appel récursif. Si cette condition est remplie, la fonction renvoie une valeur et cesse de s'appeler.
Comment fonctionne la récursion en JavaScript?
Dans JavaScript, Recursion fonctionne en appelant la fonction elle-même jusqu'à ce que la situation de base soit atteinte. La fonction est divisée en cas de base et cas récursif. Le cas de base renvoie une valeur sans appeler à nouveau la fonction, tandis que le cas récursif appelle à nouveau la fonction avec différents paramètres. La fonction continue de s'appeler jusqu'à ce que le bo?tier de base soit atteint, à quel point il commence à renvoyer la valeur.
Qu'est-ce que la récursion de la queue en javascript?
La récursivité de la queue est un type spécial de récursivité, où l'appel récursif est la dernière opération de la fonction. Ceci est important car il permet à l'optimisation du moteur JavaScript de se concrétiser, en utilisant une technique appelée optimisation des appels de queue. Cela peut réduire considérablement la quantité de mémoire utilisée par la fonction, ce qui lui permet de gérer des entrées plus grandes.
Quels sont les avantages et les inconvénients de l'utilisation de la récursivité en JavaScript?
La récursivité peut rendre le code plus concis et facile à comprendre en divisant des problèmes complexes en problèmes plus simples. Il est particulièrement utile pour les taches telles que la traversée des structures de données d'arbres. Cependant, la récursivité peut également être moins efficace que les solutions itératives, et si elle est implémentée de manière incorrecte, elle peut entra?ner une erreur de débordement de pile.
Comment éviter les erreurs de débordement de pile dans les fonctions récursives?
Lorsque la fonction récursive s'appelle trop de fois et remplit la pile d'appels, une erreur de débordement de pile se produira. Pour éviter cela, assurez-vous que votre fonction récursive a le cas de base qui finira par arriver. Envisagez également d'utiliser la récursivité de la queue, que le moteur JavaScript peut optimiser pour utiliser moins de mémoire.
Comment la récursivité est-elle utilisée dans la programmation fonctionnelle?
Dans la programmation fonctionnelle, la récursivité est souvent utilisée comme remplacement des boucles. étant donné que la programmation fonctionnelle décourage l'utilisation des états variables, la récursivité peut être utilisée pour effectuer des opérations répétées sans modifier aucun état.
Toutes les fonctions récursives peuvent-elles être converties en fonctions itératives?
Oui, en théorie, toutes les fonctions récursives peuvent être converties en fonctions itératives. Cependant, les versions itératives peuvent être plus complexes et difficiles à comprendre, en particulier pour les fonctions impliquant des traversées complexes d'arbres ou de graphiques.
Qu'est-ce que la récursion mutuelle en JavaScript?
La récursivité mutuelle fait référence à deux fonctions ou plus qui sont appelées les unes avec les autres dans une boucle. Cela peut être une technique puissante pour résoudre certains types de problèmes, mais il peut également être plus difficile de comprendre et de déboguer qu'une simple récursivité.
Comment déboguer les fonctions récursives dans JavaScript?
Les fonctions récursives de drainage peuvent être difficiles en raison des appels de fonction répétés. Cependant, il peut être utile d'imprimer les paramètres de la fonction et les valeurs de retour à chaque étape à l'aide de l'instruction Console.log. De plus, il est très utile d'utiliser un outil de débogueur qui vous permet d'effectuer des appels de fonction étape par étape.
Y a-t-il des considérations de performances lors de l'utilisation de la récursivité?
Oui, une fonction récursive peut ne pas être aussi efficace que son homologue itératif en raison de la surcharge des appels de fonction répétés. S'ils s'appellent trop de fois, ils peuvent également provoquer une erreur de débordement de pile. Cependant, dans de nombreux cas, la lisibilité et la simplicité d'une solution récursive peuvent l'emporter sur ces considérations de performance.
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!

Outils d'IA chauds

Undress AI Tool
Images de déshabillage gratuites

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
échangez les visages dans n'importe quelle vidéo sans effort grace à notre outil d'échange de visage AI entièrement gratuit?!

Article chaud

Outils chauds

Bloc-notes++7.3.1
éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Il existe trois fa?ons courantes d'initier des demandes HTTP dans Node.js: utilisez des modules intégrés, Axios et Node-Fetch. 1. Utilisez le module HTTP / HTTPS intégré sans dépendances, ce qui convient aux scénarios de base, mais nécessite un traitement manuel de la couture des données et de la surveillance des erreurs, tels que l'utilisation de https.get () pour obtenir des données ou envoyer des demandes de post via .write (); 2.AXIOS est une bibliothèque tierce basée sur la promesse. Il a une syntaxe concise et des fonctions puissantes, prend en charge l'async / attendre, la conversion JSON automatique, l'intercepteur, etc. Il est recommandé de simplifier les opérations de demande asynchrones; 3.Node-Fetch fournit un style similaire à la récupération du navigateur, basé sur la promesse et la syntaxe simple

Les types de données JavaScript sont divisés en types primitifs et types de référence. Les types primitifs incluent la cha?ne, le nombre, le booléen, le nul, un non défini et le symbole. Les valeurs sont immuables et les copies sont copiées lors de l'attribution des valeurs, de sorte qu'elles ne se affectent pas; Les types de référence tels que les objets, les tableaux et les fonctions stockent les adresses de mémoire, et les variables pointant vers le même objet s'afferchent mutuellement. Le typeof et l'instance de OFF peuvent être utilisés pour déterminer les types, mais prêtent attention aux problèmes historiques de typeofnull. Comprendre ces deux types de différences peut aider à écrire un code plus stable et fiable.

Bonjour, développeurs JavaScript! Bienvenue dans JavaScript News de cette semaine! Cette semaine, nous nous concentrerons sur: le différend de marque d'Oracle avec Deno, les nouveaux objets Time JavaScript sont pris en charge par les navigateurs, les mises à jour Google Chrome et certains outils de développeurs puissants. Commen?ons! Le différend de marque d'Oracle avec la tentative de Deno Oracle d'enregistrer une marque "JavaScript" a provoqué la controverse. Ryan Dahl, le créateur de Node.js et Deno, a déposé une pétition pour annuler la marque, et il pense que JavaScript est un niveau ouvert et ne devrait pas être utilisé par Oracle

Cacheapi est un outil fourni par le navigateur pour mettre en cache les demandes de réseau, qui est souvent utilisée en conjonction avec travailleur de service pour améliorer les performances du site Web et l'expérience hors ligne. 1. Il permet aux développeurs de stocker manuellement des ressources telles que des scripts, des feuilles de style, des photos, etc.; 2. Il peut faire correspondre les réponses du cache en fonction des demandes; 3. Il prend en charge la suppression des caches spécifiques ou la nettoyage du cache entier; 4. Il peut mettre en ?uvre des stratégies de priorité de cache ou de priorité de réseau grace à l'écoute des événements Fetch; 5. Il est souvent utilisé pour le support hors ligne, accélérez la vitesse d'accès répétée, préchargement des ressources clés et du contenu de mise à jour des antécédents; 6. Lorsque vous l'utilisez, vous devez faire attention au contr?le de la version du cache, aux restrictions de stockage et à la différence entre le mécanisme de mise en cache HTTP.

La promesse est le mécanisme central pour gérer les opérations asynchrones en JavaScript. Comprendre les appels de cha?ne, la gestion des erreurs et les combinants est la clé pour ma?triser leurs applications. 1. L'appel de la cha?ne renvoie une nouvelle promesse à travers. Puis () pour réaliser la concaténation des processus asynchrones. Chaque .then () re?oit le résultat précédent et peut renvoyer une valeur ou une promesse; 2. La gestion des erreurs doit utiliser .catch () pour attraper des exceptions pour éviter les défaillances silencieuses, et peut renvoyer la valeur par défaut dans Catch pour continuer le processus; 3. Combinateurs tels que promesse.all () (réussi avec succès uniquement après tout succès), promesse.race () (le premier achèvement est retourné) et promesse.allsetTled () (en attente de toutes les achèvements)

Des méthodes intégrées de la matrice JavaScript telles que .map (), .filter () et .reduce () peuvent simplifier le traitement des données; 1) .map () est utilisé pour convertir les éléments un en un pour générer de nouveaux tableaux; 2) .filter () est utilisé pour filtrer les éléments par condition; 3) .reduce () est utilisé pour agréger les données en tant que valeur unique; Une mauvaise utilisation doit être évitée lorsqu'elle est utilisée, entra?nant des effets secondaires ou des problèmes de performance.

La boucle d'événement de JavaScript gère les opérations asynchrones en coordonnant les piles d'appels, les webapis et les files d'attente de taches. 1. La pile d'appels exécute du code synchrone, et lors de la rencontre de taches asynchrones, il est remis à WebAPI pour le traitement; 2. Une fois que le WebAPI a terminé la tache en arrière-plan, il met le rappel dans la file d'attente correspondante (macro tache ou micro tache); 3. La boucle d'événement vérifie si la pile d'appels est vide. S'il est vide, le rappel est retiré de la file d'attente et poussé dans la pile d'appels pour l'exécution; 4. Micro taches (comme Promise. puis) ??prendre la priorité sur les taches macro (telles que Settimeout); 5. Comprendre la boucle d'événements permet d'éviter de bloquer le thread principal et d'optimiser l'ordre d'exécution du code.

Les bulles d'événements se propagent de l'élément cible vers l'extérieur vers le n?ud d'ancêtre, tandis que la capture d'événements se propage de la couche externe vers l'intérieur vers l'élément cible. 1. événements Bubbles: Après avoir cliqué sur l'élément enfant, l'événement déclenche l'auditeur de l'élément parent vers le haut. Par exemple, après avoir cliqué sur le bouton, il sortira d'abord cliqué sur l'enfant, puis parent. 2. Capture d'événement: définissez le troisième paramètre sur true, afin que l'auditeur soit exécuté dans l'étape de capture, tels que le déclenchement de l'écouteur de capture de l'élément parent avant de cliquer sur le bouton. 3. Les utilisations pratiques incluent la gestion unifiée des événements d'éléments enfants, le prétraitement d'interception et l'optimisation des performances. 4. Le flux d'événements DOM est divisé en trois étapes: capture, cible et bulle, et l'écouteur par défaut est exécuté dans l'étape de la bulle.
