diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/source.js b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/source.js index 38da0105f..7dc2bbcfa 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/source.js +++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/source.js @@ -1,5 +1,5 @@ function spy(func) { - // your code + // votre code } diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md index 19a072014..e08e1775c 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md @@ -1 +1 @@ -Here we can use `calls.push(args)` to store all arguments in the log and `f.apply(this, args)` to forward the call. +Ici, nous pouvons utiliser `calls.push(args)` pour stocker tous les arguments dans le log et `f.apply(this, args)` pour transférer l'appel. \ No newline at end of file diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md index a3843107c..f792a1134 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md @@ -2,17 +2,17 @@ importance: 5 --- -# Spy decorator +# Décorateur spy -Create a decorator `spy(func)` that should return a wrapper that saves all calls to function in its `calls` property. +Créez un décorateur `spy(func)` qui devrait renvoyer un wrapper qui enregistre tous les appels à la fonction dans sa propriété `calls`. -Every call is saved as an array of arguments. +Chaque appel est enregistré sous la forme d'un tableau d'arguments. -For instance: +Par exemple: ```js function work(a, b) { - alert( a + b ); // work is an arbitrary function or method + alert( a + b ); // work est une fonction ou une méthode arbitraire } *!* @@ -27,4 +27,4 @@ for (let args of work.calls) { } ``` -P.S. That decorator is sometimes useful for unit-testing. Its advanced form is `sinon.spy` in [Sinon.JS](http://sinonjs.org/) library. +P.S. Ce décorateur est parfois utile pour les tests unitaires. Sa forme avancée est `sinon.spy` dans la bibliothèque [Sinon.JS](http://sinonjs.org/). diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md index 24bb4d448..c189234b8 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md @@ -1,4 +1,4 @@ -The solution: +La solution: ```js run demo function delay(f, ms) { @@ -11,22 +11,22 @@ function delay(f, ms) { let f1000 = delay(alert, 1000); -f1000("test"); // shows "test" after 1000ms +f1000("test"); // montre "test" après 1000ms ``` -Please note how an arrow function is used here. As we know, arrow functions do not have own `this` and `arguments`, so `f.apply(this, arguments)` takes `this` and `arguments` from the wrapper. +Veuillez noter comment une fonction fléchée est utilisée ici. Comme nous le savons, les fonctions fléchées ne possèdent pas leurs propres `this` et `arguments`, aussi `f.apply(this, arguments)` prend `this` et `arguments` du wrapper. -If we pass a regular function, `setTimeout` would call it without arguments and `this=window` (assuming we're in the browser). +Si nous passons une fonction régulière, `setTimeout` l'appellera sans arguments et `this = window` (en supposant que nous sommes dans le navigateur). -We still can pass the right `this` by using an intermediate variable, but that's a little bit more cumbersome: +Nous pouvons toujours passer le bon `this` en utilisant une variable intermédiaire, mais c'est un peu plus lourd: ```js function delay(f, ms) { return function(...args) { - let savedThis = this; // store this into an intermediate variable + let savedThis = this; // stocker "this" dans une variable intermédiaire setTimeout(function() { - f.apply(savedThis, args); // use it here + f.apply(savedThis, args); // utilisez-le ici }, ms); }; diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/task.md index c04c68d7e..d6c20918e 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/task.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/task.md @@ -2,25 +2,25 @@ importance: 5 --- -# Delaying decorator +# Décorateur de retardement -Create a decorator `delay(f, ms)` that delays each call of `f` by `ms` milliseconds. +Créez un décorateur `delay(f, ms)` qui retarde chaque appel de `f` de `ms` millisecondes. -For instance: +Par exemple: ```js function f(x) { alert(x); } -// create wrappers +// créer des wrappers let f1000 = delay(f, 1000); let f1500 = delay(f, 1500); -f1000("test"); // shows "test" after 1000ms -f1500("test"); // shows "test" after 1500ms +f1000("test"); // montre "test" après 1000ms +f1500("test"); // montre "test" après 1500ms ``` -In other words, `delay(f, ms)` returns a "delayed by `ms`" variant of `f`. +En d'autres termes, `delay(f, ms)` renvoie une variante "retardée de `ms`" de `f`. -In the code above, `f` is a function of a single argument, but your solution should pass all arguments and the context `this`. +Dans le code ci-dessus, `f` est une fonction d'un seul argument, mais votre solution doit transmettre tous les arguments et le contexte `this`. \ No newline at end of file diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md index 4f5867ded..68ace0d77 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md @@ -16,13 +16,13 @@ function debounce(f, ms) { } ``` -A call to `debounce` returns a wrapper. There may be two states: +Un appel à `debounce` renvoie un wrapper. Il peut y avoir deux états: -- `isCooldown = false` -- ready to run. -- `isCooldown = true` -- waiting for the timeout. +- `isCooldown = false` -- prêt à exécuter. +- `isCooldown = true` -- en attente du timeout. -In the first call `isCooldown` is falsy, so the call proceeds, and the state changes to `true`. +Lors du premier appel, `is Cooldown` est fausse. L'appel se poursuit et l'état passe à` true`. -While `isCooldown` is true, all other calls are ignored. +Alors que `isCooldown` est vrai, tous les autres appels sont ignorés. -Then `setTimeout` reverts it to `false` after the given delay. +Ensuite, `setTimeout` le rétablit à `false` après le délai imparti. diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md index 466c6bc3f..a1752ad63 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md @@ -2,23 +2,23 @@ importance: 5 --- -# Debounce decorator +# Décorateur debounce -The result of `debounce(f, ms)` decorator should be a wrapper that passes the call to `f` at maximum once per `ms` milliseconds. +Le résultat du décorateur `debounce(f, ms)` devrait être un wrapper qui transmet l'appel à `f` au maximum une fois par `ms`, millisecondes. -In other words, when we call a "debounced" function, it guarantees that all other future in the closest `ms` milliseconds will be ignored. +En d’autres termes, lorsque nous appelons une fonction "debounce", elle garantit que tous les autres appels futurs dans les millisecondes `ms` les plus proches seront ignorés. -For instance: +Par exemple: ```js no-beautify let f = debounce(alert, 1000); -f(1); // runs immediately -f(2); // ignored +f(1); // exécute immédiatement +f(2); // ignorée -setTimeout( () => f(3), 100); // ignored ( only 100 ms passed ) -setTimeout( () => f(4), 1100); // runs -setTimeout( () => f(5), 1500); // ignored (less than 1000 ms from the last run) +setTimeout( () => f(3), 100); // ignorée (seulement 100 ms passé) +setTimeout( () => f(4), 1100); // exécute +setTimeout( () => f(5), 1500); // ignorée (moins de 1000 ms à partir de la dernière exécution) ``` -In practice `debounce` is useful for functions that retrieve/update something when we know that nothing new can be done in such a short period of time, so it's better not to waste resources. \ No newline at end of file +En pratique, `debounce` est utile pour les fonctions qui récupèrent/mettent à jour quelque chose quand on sait que rien de nouveau ne peut être fait dans un laps de temps aussi court, il est donc préférable de ne pas gaspiller de ressources. \ No newline at end of file diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/solution.js b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/solution.js index 8071be9d4..d026838f0 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/solution.js +++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/solution.js @@ -7,23 +7,23 @@ function throttle(func, ms) { function wrapper() { if (isThrottled) { - // memo last arguments to call after the cooldown + // mémo derniers arguments à appeler après le temps de recharge savedArgs = arguments; savedThis = this; return; } - // otherwise go to cooldown state + // sinon aller en état de recharge func.apply(this, arguments); isThrottled = true; - // plan to reset isThrottled after the delay + // prévoir de réinitialiser isThrottled après le délai setTimeout(function() { isThrottled = false; if (savedArgs) { - // if there were calls, savedThis/savedArgs have the last one - // recursive call runs the function and sets cooldown again + // s'il y a eu des appels, savedThis/savedArgs auront le dernier + // appel récursif exécute la fonction et redéfinit le temps de recharge wrapper.apply(savedThis, savedArgs); savedArgs = savedThis = null; } diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md index c844016d3..db106731d 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md @@ -30,10 +30,10 @@ function throttle(func, ms) { } ``` -A call to `throttle(func, ms)` returns `wrapper`. +Un appel à `throttle(func, ms)` retourne `wrapper`. -1. During the first call, the `wrapper` just runs `func` and sets the cooldown state (`isThrottled = true`). -2. In this state all calls memorized in `savedArgs/savedThis`. Please note that both the context and the arguments are equally important and should be memorized. We need them simultaneously to reproduce the call. -3. ...Then after `ms` milliseconds pass, `setTimeout` triggers. The cooldown state is removed (`isThrottled = false`). And if we had ignored calls, then `wrapper` is executed with last memorized arguments and context. +1. Lors du premier appel, le `wrapper` exécute simplement `func` et définit l'état de refroidissement (`isThrottled = true`). +2. Dans cet état, tous les appels sont mémorisés dans `savedArgs/savedThis`. Veuillez noter que le contexte et les arguments sont d'égale importance et doivent être mémorisés. Nous avons besoin d'eux simultanément pour reproduire l'appel. +3. ...Ensuite, après le passage de `ms` millisecondes,`setTimeout` se déclenche. L'état de refroidissement est supprimé (`isThrottled = false`). Et si nous avions ignoré les appels, alors `wrapper` est exécuté avec les derniers arguments et contextes mémorisés. -The 3rd step runs not `func`, but `wrapper`, because we not only need to execute `func`, but once again enter the cooldown state and setup the timeout to reset it. +La 3ème étape n’exécute pas `func`, mais `wrapper`, car nous devons non seulement exécuter `func`, mais encore une fois entrer dans l’état de refroidissement et configurer le délai d’expiration pour le réinitialiser. diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md index 8dd77368d..73c03a2eb 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md @@ -2,47 +2,47 @@ importance: 5 --- -# Throttle decorator +# Décorateur d'étranglement -Create a "throttling" decorator `throttle(f, ms)` -- that returns a wrapper, passing the call to `f` at maximum once per `ms` milliseconds. Those calls that fall into the "cooldown" period, are ignored. +Créez un décorateur "d'étranglement" `throttle(f, ms)` - qui retourne un wrapper, en passant l'appel à `f` au maximum une fois par `ms` millisecondes. Les appels qui tombent dans le "temps de recharge" sont ignorés. -**The difference with `debounce` -- if an ignored call is the last during the cooldown, then it executes at the end of the delay.** +**La différence avec `debounce` - si un appel ignoré est le dernier pendant le temps de recharge, il s'exécute à la fin du délai.** -Let's check the real-life application to better understand that requirement and to see where it comes from. +Examinons l'application réelle pour mieux comprendre cette exigence et voir d'où elle vient. -**For instance, we want to track mouse movements.** +**Par exemple, nous voulons suivre les mouvements de la souris.** -In browser we can setup a function to run at every mouse movement and get the pointer location as it moves. During an active mouse usage, this function usually runs very frequently, can be something like 100 times per second (every 10 ms). +Dans le navigateur, nous pouvons configurer une fonction à exécuter à chaque mouvement de la souris et obtenir l’emplacement du pointeur à mesure qu’il se déplace. Pendant une utilisation active de la souris, cette fonction est généralement utilisée très souvent et peut atteindre 100 fois par seconde (toutes les 10 ms). -**The tracking function should update some information on the web-page.** +**La fonction de suivi devrait mettre à jour certaines informations sur la page Web.** -Updating function `update()` is too heavy to do it on every micro-movement. There is also no sense in making it more often than once per 100ms. +La mise à jour de la fonction `update()` est trop lourde pour le faire à chaque micro-mouvement. Cela n’a également aucun sens de le faire plus d’une fois toutes les 100 ms. -So we'll wrap it into the decorator: use `throttle(update, 100)` as the function to run on each mouse move instead of the original `update()`. The decorator will be called often, but `update()` will be called at maximum once per 100ms. +Nous allons donc l'envelopper dans le décorateur: utilisez `throttle(update, 100)` comme fonction à exécuter à chaque déplacement de souris à la place de `update()` d'origine. Le décorateur sera appelé souvent, mais `update()` sera appelé au maximum une fois toutes les 100 ms. -Visually, it will look like this: +Visuellement, cela ressemblera à ceci: -1. For the first mouse movement the decorated variant passes the call to `update`. That's important, the user sees our reaction to their move immediately. -2. Then as the mouse moves on, until `100ms` nothing happens. The decorated variant ignores calls. -3. At the end of `100ms` -- one more `update` happens with the last coordinates. -4. Then, finally, the mouse stops somewhere. The decorated variant waits until `100ms` expire and then runs `update` with last coordinates. So, perhaps the most important, the final mouse coordinates are processed. +1. Pour le premier mouvement de souris, la variante décorée passe l'appel à `update`. Cela est important, l'utilisateur voit notre réaction à leur mouvement immédiatement. +2. Puis, alors que la souris continue d'avancer, il ne se passe plus rien jusqu'à 100ms. La variante décorée ignore les appels. +3. À la fin de `100ms` - une autre `update` se produit avec les dernières coordonnées. +4. Enfin, la souris s’arrête quelque part. La variante décorée attend que `100ms` expire, puis lance `update` avec les dernières coordonnées. Donc, peut-être le plus important, les coordonnées finales de la souris sont traitées. -A code example: +Un exemple de code: ```js function f(a) { console.log(a) }; -// f1000 passes calls to f at maximum once per 1000 ms +// f1000 passe les appels à f au maximum une fois toutes les 1000 ms let f1000 = throttle(f, 1000); -f1000(1); // shows 1 -f1000(2); // (throttling, 1000ms not out yet) -f1000(3); // (throttling, 1000ms not out yet) +f1000(1); // montre 1 +f1000(2); // (étranglement, 1000ms pas encore écoulée) +f1000(3); // (étranglement, 1000ms pas encore écoulée) -// when 1000 ms time out... -// ...outputs 3, intermediate value 2 was ignored +// quand 1000ms expirent... +// ...sort 3, la valeur intermédiaire 2 a été ignorée ``` -P.S. Arguments and the context `this` passed to `f1000` should be passed to the original `f`. +P.S. Les arguments et le contexte `this` transmis à `f1000` doivent être transmis à `f` d'origine. diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/article.md b/1-js/06-advanced-functions/09-call-apply-decorators/article.md index 33a4bb8f3..c598c5dde 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/article.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/article.md @@ -1,20 +1,20 @@ -# Decorators and forwarding, call/apply +# Décorateurs et transferts, call/apply -JavaScript gives exceptional flexibility when dealing with functions. They can be passed around, used as objects, and now we'll see how to *forward* calls between them and *decorate* them. +JavaScript offre une flexibilité exceptionnelle dans le traitement des fonctions. Elles peuvent être échangées, utilisés comme objets, et maintenant nous allons voir comment *transférer* les appels entre eux et *les décorer*. -## Transparent caching +## Cache transparent -Let's say we have a function `slow(x)` which is CPU-heavy, but its results are stable. In other words, for the same `x` it always returns the same result. +Disons que nous avons une fonction `slow(x)` qui nécessite beaucoup de ressources processeur, mais ses résultats sont stables. En d'autres termes, pour le même `x`, le résultat est toujours le même. -If the function is called often, we may want to cache (remember) the results for different `x` to avoid spending extra-time on recalculations. +Si la fonction est appelée souvent, on peut vouloir mettre en cache (mémoriser) les résultats pour les différents `x` pour éviter des dépenses supplémentaires en temps sur recalcul. -But instead of adding that functionality into `slow()` we'll create a wrapper. As we'll see, there are many benefits of doing so. +Mais au lieu d’ajouter cette fonctionnalité à `slow()`, nous allons créer un wrapper. Comme nous le verrons, cela présente de nombreux avantages. -Here's the code, and explanations follow: +Voici le code, et les explications suivent: ```js run function slow(x) { - // there can be a heavy CPU-intensive job here + // il peut y avoir un travail gourmand en ressources processeur ici alert(`Called with ${x}`); return x; } @@ -23,68 +23,68 @@ function cachingDecorator(func) { let cache = new Map(); return function(x) { - if (cache.has(x)) { // if the result is in the map - return cache.get(x); // return it + if (cache.has(x)) { // si le résultat est dans le map + return cache.get(x); // renvoie le } - let result = func(x); // otherwise call func + let result = func(x); // autrement, appel func - cache.set(x, result); // and cache (remember) the result + cache.set(x, result); // et cache (mémorise) le résultat return result; }; } slow = cachingDecorator(slow); -alert( slow(1) ); // slow(1) is cached -alert( "Again: " + slow(1) ); // the same +alert( slow(1) ); // slow(1) est mise en cache +alert( "Again: " + slow(1) ); // pareil -alert( slow(2) ); // slow(2) is cached -alert( "Again: " + slow(2) ); // the same as the previous line +alert( slow(2) ); // slow(2) est mise en cache +alert( "Again: " + slow(2) ); // pareil que la ligne précédente ``` -In the code above `cachingDecorator` is a *decorator*: a special function that takes another function and alters its behavior. +Dans le code ci-dessus, `cachingDecorator` est un *décorateur*: une fonction spéciale qui prend une autre fonction et modifie son comportement. -The idea is that we can call `cachingDecorator` for any function, and it will return the caching wrapper. That's great, because we can have many functions that could use such a feature, and all we need to do is to apply `cachingDecorator` to them. +L'idée est que nous pouvons appeler `cachingDecorator` pour n'importe quelle fonction, ce qui renverra le wrapper de mise en cache. C'est formidable, car nous pouvons avoir de nombreuses fonctions qui pourraient utiliser une telle fonctionnalité, et tout ce que nous avons à faire est de leur appliquer `cachingDecorator`. -By separating caching from the main function code we also keep the main code simpler. +En séparant la mise en cache du code de la fonction principale, nous simplifions également le code principal. -Now let's get into details of how it works. +Regardons de plus près les détails de son fonctionnement. -The result of `cachingDecorator(func)` is a "wrapper": `function(x)` that "wraps" the call of `func(x)` into caching logic: +Le résultat de `cachingDecorator(func)` est un "wrapper": `function(x)` qui "encapsule" l'appel de `func(x)` dans la logique de mise en cache: ![](decorator-makecaching-wrapper.png) -As we can see, the wrapper returns the result of `func(x)` "as is". From an outside code, the wrapped `slow` function still does the same. It just got a caching aspect added to its behavior. +Comme nous pouvons le constater, le wrapper renvoie le résultat de `func(x)` "tel quel". Depuis un code extérieur, la fonction `slow` encapsulée fait toujours la même chose. Un comportement de mise en cache vient d’être ajouté à son comportement. -To summarize, there are several benefits of using a separate `cachingDecorator` instead of altering the code of `slow` itself: +Pour résumer, il y a plusieurs avantages à utiliser un `cachingDecorator` distinct au lieu de modifier le code de `slow` lui-même: -- The `cachingDecorator` is reusable. We can apply it to another function. -- The caching logic is separate, it did not increase the complexity of `slow` itself (if there were any). -- We can combine multiple decorators if needed (other decorators will follow). +- Le `cachingDecorator` est réutilisable. Nous pouvons l'appliquer à une autre fonction. +- La logique de mise en cache est séparée, elle n’a pas augmenté la complexité de `slow` lui-même (s’il en existait) +- Nous pouvons combiner plusieurs décorateurs si nécessaire (d'autres décorateurs suivront). -## Using "func.call" for the context +## L'utilisation de « func.call » pour le contexte -The caching decorator mentioned above is not suited to work with object methods. +Le décorateur de mise en cache mentionné ci-dessus n'est pas adapté pour travailler avec des méthodes d'objet. -For instance, in the code below `worker.slow()` stops working after the decoration: +Par exemple, dans le code ci-dessous `worker.slow()` cesse de fonctionner après la décoration: ```js run -// we'll make worker.slow caching +// on ajoutera une fonctionalité de cache à worker.slow let worker = { someMethod() { return 1; }, slow(x) { - // actually, there can be a scary CPU-heavy task here + // en fait, il peut y avoir une tâche lourde ici alert("Called with " + x); return x * this.someMethod(); // (*) } }; -// same code as before +// même code que précédemment function cachingDecorator(func) { let cache = new Map(); return function(x) { @@ -99,49 +99,49 @@ function cachingDecorator(func) { }; } -alert( worker.slow(1) ); // the original method works +alert( worker.slow(1) ); // la méthode originale fonctionne -worker.slow = cachingDecorator(worker.slow); // now make it caching +worker.slow = cachingDecorator(worker.slow); // ajoute la mise en cache *!* alert( worker.slow(2) ); // Whoops! Error: Cannot read property 'someMethod' of undefined */!* ``` -The error occurs in the line `(*)` that tries to access `this.someMethod` and fails. Can you see why? +L'erreur se produit dans la ligne `(*)` qui tente d'accéder à `this.someMethod` et échoue. Pouvez-vous voir pourquoi? -The reason is that the wrapper calls the original function as `func(x)` in the line `(**)`. And, when called like that, the function gets `this = undefined`. +La raison en est que le wrapper appelle la fonction d'origine sous la forme `func(x)` dans la ligne `(**)`. Et, lorsqu'elle est appelée comme ça, la fonction obtient `this = undefined`. -We would observe a similar symptom if we tried to run: +Nous observerions un symptôme similaire si nous essayions d'executer: ```js let func = worker.slow; func(2); ``` -So, the wrapper passes the call to the original method, but without the context `this`. Hence the error. +Ainsi, le wrapper passe l'appel à la méthode d'origine, mais sans le contexte `this`. D'où l'erreur. -Let's fix it. +Réparons-le. -There's a special built-in function method [func.call(context, ...args)](mdn:js/Function/call) that allows to call a function explicitly setting `this`. +Il existe une méthode de fonction intégrée spéciale [func.call(context, ...args)](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Function/call) qui permet d'appeler explicitement une fonction en définissant `this`. -The syntax is: +La syntaxe est la suivante: ```js func.call(context, arg1, arg2, ...) ``` -It runs `func` providing the first argument as `this`, and the next as the arguments. +Il exécute `func` en fournissant `this` comme le premier argument et les suivants en tant qu'arguments. -To put it simply, these two calls do almost the same: +Pour le dire simplement, ces deux appels font presque la même chose: ```js func(1, 2, 3); func.call(obj, 1, 2, 3) ``` -They both call `func` with arguments `1`, `2` and `3`. The only difference is that `func.call` also sets `this` to `obj`. +Ils appellent tous les deux `func` avec les arguments `1`, `2` et `3`. La seule différence est que `func.call` définit également `this` sur `obj`. -As an example, in the code below we call `sayHi` in the context of different objects: `sayHi.call(user)` runs `sayHi` providing `this=user`, and the next line sets `this=admin`: +Par exemple, dans le code ci-dessous, nous appelons `sayHi` dans le contexte de différents objets: `sayHi.call(user)` exécute `sayHi` fournissant `this = user`, et la ligne suivante définit `this = admin`: ```js run function sayHi() { @@ -151,12 +151,12 @@ function sayHi() { let user = { name: "John" }; let admin = { name: "Admin" }; -// use call to pass different objects as "this" +// utilisez call pour passer différents objets en tant que "this" sayHi.call( user ); // this = John sayHi.call( admin ); // this = Admin ``` -And here we use `call` to call `say` with the given context and phrase: +Et ici, nous utilisons `call` pour appeler `say` avec le contexte et la phrase donnés: ```js run @@ -166,12 +166,12 @@ function say(phrase) { let user = { name: "John" }; -// user becomes this, and "Hello" becomes the first argument +// user devient this, et "Hello" devient le premier argument say.call( user, "Hello" ); // John: Hello ``` -In our case, we can use `call` in the wrapper to pass the context to the original function: +Dans notre cas, nous pouvons utiliser `call` dans le wrapper pour passer le contexte à la fonction d'origine: ```js run @@ -193,80 +193,80 @@ function cachingDecorator(func) { return cache.get(x); } *!* - let result = func.call(this, x); // "this" is passed correctly now + let result = func.call(this, x); // "this" est passé correctement maintenant */!* cache.set(x, result); return result; }; } -worker.slow = cachingDecorator(worker.slow); // now make it caching +worker.slow = cachingDecorator(worker.slow); // ajoute la mise en cache -alert( worker.slow(2) ); // works -alert( worker.slow(2) ); // works, doesn't call the original (cached) +alert( worker.slow(2) ); // ça fonctione +alert( worker.slow(2) ); // ça fonctionne, n'appelle pas l'original (mis en cache) ``` -Now everything is fine. +Maintenant, tout va bien. -To make it all clear, let's see more deeply how `this` is passed along: +Pour que tout soit clair, voyons plus en détail comment `this` est passé: -1. After the decoration `worker.slow` is now the wrapper `function (x) { ... }`. -2. So when `worker.slow(2)` is executed, the wrapper gets `2` as an argument and `this=worker` (it's the object before dot). -3. Inside the wrapper, assuming the result is not yet cached, `func.call(this, x)` passes the current `this` (`=worker`) and the current argument (`=2`) to the original method. +1. Après la décoration, `worker.slow` est désormais le wrapper `function(x) {...}`. +2. Ainsi, lorsque `worker.slow(2)` est exécuté, le wrapper obtient `2` en argument et `this = worker` (c'est l'objet avant le point). +3. Dans le wrapper, en supposant que le résultat ne soit pas encore mis en cache, `func.call(this, x)` passe le `this` (`= worker`) actuel et l'argument actuel (`= 2`) à la méthode d'origine. . -## Going multi-argument with "func.apply" +## Passer plusieurs argument avec "func.apply" -Now let's make `cachingDecorator` even more universal. Till now it was working only with single-argument functions. +Rendons maintenant `cachingDecorator` encore plus universel. Jusqu'à présent, il ne travaillait qu'avec des fonctions à un seul argument. -Now how to cache the multi-argument `worker.slow` method? +Maintenant, comment mettre en cache la méthode multi-argument `worker.slow`? ```js let worker = { slow(min, max) { - return min + max; // scary CPU-hogger is assumed + return min + max; // tache lourde est supposé } }; -// should remember same-argument calls +// devrait se rappeler des appels au mêmes arguments worker.slow = cachingDecorator(worker.slow); ``` -We have two tasks to solve here. +Nous avons deux tâches à résoudre ici. -First is how to use both arguments `min` and `max` for the key in `cache` map. Previously, for a single argument `x` we could just `cache.set(x, result)` to save the result and `cache.get(x)` to retrieve it. But now we need to remember the result for a *combination of arguments* `(min,max)`. The native `Map` takes single value only as the key. +Premièrement, comment utiliser les deux arguments `min` et` max` pour la clé dans le `Map` `cache`. Auparavant, pour un seul argument, `x`, nous pouvions simplement `cache.set(x, result)` pour enregistrer le résultat et `cache.get(x)` pour le récupérer. Mais maintenant, nous devons nous rappeler le résultat pour une *combinaison d'arguments* `(min, max)`. Le `Map` natif prend une valeur unique en tant que clé. -There are many solutions possible: +Il y a beaucoup de solutions possibles: -1. Implement a new (or use a third-party) map-like data structure that is more versatile and allows multi-keys. -2. Use nested maps: `cache.set(min)` will be a `Map` that stores the pair `(max, result)`. So we can get `result` as `cache.get(min).get(max)`. -3. Join two values into one. In our particular case we can just use a string `"min,max"` as the `Map` key. For flexibility, we can allow to provide a *hashing function* for the decorator, that knows how to make one value from many. +1. Mettre en œuvre une nouvelle structure de données similaire à `Map` (ou utiliser une par une tierce partie) plus polyvalent et permetant l'utilisation de plusieurs clés. +2. Utilisez des maps imbriquées: `cache.set(min)` sera un `Map` qui stocke la paire `(max, result)`. Donc, nous pouvons obtenir `result` avec `cache.get (min).get(max)`. +3. Joignez deux valeurs en une. Dans notre cas particulier, nous pouvons simplement utiliser la chaîne `"min, max"` comme clé pour `Map`. Pour plus de flexibilité, nous pouvons permettre de fournir une *fonction de hachage* au décorateur, qui sait créer une valeur parmi plusieurs. -For many practical applications, the 3rd variant is good enough, so we'll stick to it. +Pour de nombreuses applications pratiques, la 3ème variante est suffisante, nous allons donc nous y tenir. -The second task to solve is how to pass many arguments to `func`. Currently, the wrapper `function(x)` assumes a single argument, and `func.call(this, x)` passes it. +La deuxième tâche à résoudre consiste à passer de nombreux arguments à `func`. Actuellement, le wrapper `function(x)` suppose un seul argument et `func.call(this, x)` le passe. -Here we can use another built-in method [func.apply](mdn:js/Function/apply). +Ici, nous pouvons utiliser une autre méthode intégrée [func.apply](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Function/apply). -The syntax is: +La syntaxe est la suivante: ```js func.apply(context, args) ``` -It runs the `func` setting `this=context` and using an array-like object `args` as the list of arguments. +Ça exécute le paramètre `func` avec `this = context` et utilise un objet de type tableau `args` comme liste d'arguments. -For instance, these two calls are almost the same: +Par exemple, ces deux appels sont presque les mêmes: ```js func(1, 2, 3); func.apply(context, [1, 2, 3]) ``` -Both run `func` giving it arguments `1,2,3`. But `apply` also sets `this=context`. +Les deux exécutent `func` en lui donnant les arguments `1,2,3`. Mais `apply` définit également `this = context`. -For instance, here `say` is called with `this=user` and `messageData` as a list of arguments: +Par exemple, ici, `say` est appelé avec `this = user` et `messageData` en tant que liste d'arguments: ```js run function say(time, phrase) { @@ -275,39 +275,39 @@ function say(time, phrase) { let user = { name: "John" }; -let messageData = ['10:00', 'Hello']; // become time and phrase +let messageData = ['10:00', 'Hello']; // devient time et phrase *!* -// user becomes this, messageData is passed as a list of arguments (time, phrase) +// user devient this, messageData est passé sous forme de liste d'arguments (time, phrase) say.apply(user, messageData); // [10:00] John: Hello (this=user) */!* ``` -The only syntax difference between `call` and `apply` is that `call` expects a list of arguments, while `apply` takes an array-like object with them. +La seule différence de syntaxe entre `call` et `apply` est que `call` attend une liste d'arguments, tandis que `apply` prend un objet de type tableau avec les arguments. -We already know the spread operator `...` from the chapter that can pass an array (or any iterable) as a list of arguments. So if we use it with `call`, we can achieve almost the same as `apply`. +Nous connaissons déjà l'opérateur de decomposition `...` du chapitre qui permet d'etendre un tableau (ou tout élément itérable) sous forme de liste d'arguments. Donc, si nous l'utilisons avec `call`, nous pouvons presque obtenir le même résultat que `apply`. -These two calls are almost equivalent: +Ces deux appels sont presque équivalents: ```js let args = [1, 2, 3]; *!* -func.call(context, ...args); // pass an array as list with spread operator -func.apply(context, args); // is same as using apply +func.call(context, ...args); // passer un tableau sous forme de liste avec l'opérateur de décomposition +func.apply(context, args); // est la même que l'utilisation de apply */!* ``` -If we look more closely, there's a minor difference between such uses of `call` and `apply`. +Si nous regardons de plus près, il y a une différence mineure entre de telles utilisations de `call` et de `apply`. -- The spread operator `...` allows to pass *iterable* `args` as the list to `call`. -- The `apply` accepts only *array-like* `args`. +- L'opérateur de decomposition `...` permet de passer des `args` *itérables* comme liste à `call`. +- La commande `apply` accepte uniquement les *objets semblables à des tableaux* comme `args`. -So, these calls complement each other. Where we expect an iterable, `call` works, where we expect an array-like, `apply` works. +Donc, ces appels se complémente mutuellement. Là où nous nous attendons à un itérable, `call` fonctionne, alors que là ou nous nous attendons à un tableau, `apply` fonctionne. -And if `args` is both iterable and array-like, like a real array, then we technically could use any of them, but `apply` will probably be faster, because it's a single operation. Most JavaScript engines internally optimize it better than a pair `call + spread`. +Et si `args` est à la fois itérable et semblable à un tableau, à la manière d'un vrai tableau, nous pourrions techniquement utiliser n'importe lequel d'entre eux, mais `apply` sera probablement plus rapide, car il s'agit d'une opération unique. La plupart des moteurs JavaScript l'optimisent en interne mieux qu'un couple `appel + decomposition`. -One of the most important uses of `apply` is passing the call to another function, like this: +Une des utilisations les plus importantes de `apply` est de passer l'appel à une autre fonction, comme ceci: ```js let wrapper = function() { @@ -315,11 +315,11 @@ let wrapper = function() { }; ``` -That's called *call forwarding*. The `wrapper` passes everything it gets: the context `this` and arguments to `anotherFunction` and returns back its result. +Cela s'appelle *call forwarding* (renvoi d'appel). Le `wrapper` passe tout ce qu'il a: le contexte `this` et les arguments de `anotherFunction` et renvoie le résultat. -When an external code calls such `wrapper`, it is indistinguishable from the call of the original function. +Lorsqu'un code externe appelle un tel `wrapper`, il est impossible de le distinguer de l'appel de la fonction d'origine. -Now let's bake it all into the more powerful `cachingDecorator`: +Intégrons maintenant le tout dans le plus puissant `cachingDecorator`: ```js run let worker = { @@ -354,21 +354,21 @@ function hash(args) { worker.slow = cachingDecorator(worker.slow, hash); -alert( worker.slow(3, 5) ); // works -alert( "Again " + worker.slow(3, 5) ); // same (cached) +alert( worker.slow(3, 5) ); // ça marche +alert( "Again " + worker.slow(3, 5) ); // pareil (mis en cache) ``` -Now the wrapper operates with any number of arguments. +Maintenant, le wrapper fonctionne avec un nombre quelconque d'arguments. -There are two changes: +Il y a deux changements: -- In the line `(*)` it calls `hash` to create a single key from `arguments`. Here we use a simple "joining" function that turns arguments `(3, 5)` into the key `"3,5"`. More complex cases may require other hashing functions. -- Then `(**)` uses `func.apply` to pass both the context and all arguments the wrapper got (no matter how many) to the original function. +- Dans la ligne `(*)`, il appelle `hash` pour créer une clé unique à partir de `arguments`. Ici, nous utilisons une simple fonction "d'assemblage" qui transforme les arguments `(3, 5)` en la clé `"3,5"`. Les cas plus complexes peuvent nécessiter d'autres fonctions de hachage. +- Ensuite `(**)` utilise `func.apply` pour transmettre le contexte et tous les arguments obtenus par le wrapper (peu importe le nombre) à la fonction d'origine. -## Borrowing a method [#method-borrowing] +## Emprunter une méthode [#method-borrowing] -Now let's make one more minor improvement in the hashing function: +Maintenant, apportons une autre amélioration mineure à la fonction de hachage: ```js function hash(args) { @@ -376,9 +376,9 @@ function hash(args) { } ``` -As of now, it works only on two arguments. It would be better if it could glue any number of `args`. +Pour l'instant, cela ne fonctionne que sur deux arguments. Ce serait mieux s'il pouvait coller un nombre quelconque de `args`. -The natural solution would be to use [arr.join](mdn:js/Array/join) method: +La solution naturelle serait d'utiliser la méthode [arr.join](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/join): ```js function hash(args) { @@ -386,9 +386,9 @@ function hash(args) { } ``` -...Unfortunately, that won't work. Because we are calling `hash(arguments)` and `arguments` object is both iterable and array-like, but not a real array. +... Malheureusement, ça ne marchera pas. Parce que nous appelons `hash(arguments)` et l’objet `arguments` est à la fois itérable et semblable à un tableau, mais pas un vrai tableau. -So calling `join` on it would fail, as we can see below: +Donc, appeler `join` échouerait, comme on peut le voir ci-dessous: ```js run function hash() { @@ -400,7 +400,7 @@ function hash() { hash(1, 2); ``` -Still, there's an easy way to use array join: +Néanmoins, il existe un moyen simple d’utiliser `join`: ```js run function hash() { @@ -412,40 +412,40 @@ function hash() { hash(1, 2); ``` -The trick is called *method borrowing*. +L'astuce s'appelle *method borrowing* (empruntage de méthode). -We take (borrow) a join method from a regular array `[].join`. And use `[].join.call` to run it in the context of `arguments`. +Nous empruntons la méthode `join` d'un tableau régulier `[].join`. Et utilison `[].join.call` pour l'exécuter dans le contexte de `arguments`. -Why does it work? +Pourquoi ça marche? -That's because the internal algorithm of the native method `arr.join(glue)` is very simple. +C'est parce que l'algorithme interne de la méthode native `arr.join(glue)` est très simple. -Taken from the specification almost "as-is": +Tiré de la spécification presque "tel quel": -1. Let `glue` be the first argument or, if no arguments, then a comma `","`. -2. Let `result` be an empty string. -3. Append `this[0]` to `result`. -4. Append `glue` and `this[1]`. -5. Append `glue` and `this[2]`. -6. ...Do so until `this.length` items are glued. -7. Return `result`. +1. Soit `glue` le premier argument ou, s’il n’ya pas d’argument, une virgule `","`. +2. Soit `result` une chaîne de caractères vide. +3. Ajoutez `this[0]` à `result`. +4. Ajoutez `glue` et `this[1]`. +5. Ajoutez `glue` et `this[2]`. +6. ... Faites-le jusqu'à ce que `this.length` éléments soient collés. +7. Retournez `result`. -So, technically it takes `this` and joins `this[0]`, `this[1]` ...etc together. It's intentionally written in a way that allows any array-like `this` (not a coincidence, many methods follow this practice). That's why it also works with `this=arguments`. +Donc, techniquement, cela prend `this` et associe `this[0]`, `this[1]`... etc. Il est intentionnellement écrit de manière à permettre à tout type de tableau `this` (pas une coïncidence, de nombreuses méthodes suivent cette pratique). C'est pourquoi cela fonctionne aussi avec `this = arguments`. -## Summary +## Résumé -*Decorator* is a wrapper around a function that alters its behavior. The main job is still carried out by the function. +*Decorator* est un wrapper autour d'une fonction qui modifie son comportement. Le travail principal est toujours effectué par la fonction. -It is generally safe to replace a function or a method with a decorated one, except for one little thing. If the original function had properties on it, like `func.calledCount` or whatever, then the decorated one will not provide them. Because that is a wrapper. So one needs to be careful if one uses them. Some decorators provide their own properties. +Il est généralement prudent de remplacer une fonction ou une méthode par une fonction décorée, à une exception près. Si la fonction d'origine avait des propriétés, comme `func.calledCount` ou autre chose, la fonction décorée ne les fournira pas. Parce que c'est un wrapper. Il faut donc faire attention si on les utilise. Certains décorateurs fournissent leurs propres propriétés. -Decorators can be seen as "features" or "aspects" that can be added to a function. We can add one or add many. And all this without changing its code! +Les décorateurs peuvent être considérés comme des "caractéristiques" ou des "aspects" pouvant être ajoutés à une fonction. Nous pouvons en ajouter un ou en ajouter plusieurs. Et tout ça sans changer de code! -To implement `cachingDecorator`, we studied methods: +Pour implémenter `cachingDecorator`, nous avons étudié des méthodes: -- [func.call(context, arg1, arg2...)](mdn:js/Function/call) -- calls `func` with given context and arguments. -- [func.apply(context, args)](mdn:js/Function/apply) -- calls `func` passing `context` as `this` and array-like `args` into a list of arguments. +- [func.call(context, arg1, arg2...)](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Function/call) -- appelle `func` avec un contexte et des arguments donnés. +- [func.apply(context, args)](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Function/apply) -- appelle `func` en passant `context` comme `this` et `args` sous forme de tableau dans une liste d'arguments. -The generic *call forwarding* is usually done with `apply`: +Le renvoi d'appel, *call forwarding*, est généralement effectué avec `apply`: ```js let wrapper = function() { @@ -453,7 +453,6 @@ let wrapper = function() { } ``` -We also saw an example of *method borrowing* when we take a method from an object and `call` it in the context of another object. It is quite common to take array methods and apply them to `arguments`. The alternative is to use rest parameters object that is a real array. +Nous avons également vu un exemple d'empruntage de méthode, *method borrowing*, lorsque nous prenons une méthode à partir d'un objet et que nous l'appelons dans le contexte d'un autre objet. Il est assez courant de prendre des méthodes de tableau et de les appliquer à `arguments`. L'alternative consiste à utiliser l'objet de paramètres du reste qui est un vrai tableau. - -There are many decorators there in the wild. Check how well you got them by solving the tasks of this chapter. +Il y a beaucoup de décorateurs dans la nature. Vérifiez si vous les avez bien compris en résolvant les tâches de ce chapitre.