Skip to content

Commit dc814ca

Browse files
Apply minor fixes in '1-js/06-advanced-functions/09-call-apply-decorators/article.md'
1 parent dc7a150 commit dc814ca

File tree

1 file changed

+35
-36
lines changed
  • 1-js/06-advanced-functions/09-call-apply-decorators

1 file changed

+35
-36
lines changed

1-js/06-advanced-functions/09-call-apply-decorators/article.md

Lines changed: 35 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Si la fonction est appelée souvent, nous voudrons peut-être mettre en mémoire
1010

1111
Mais au lieu d’ajouter cette fonctionnalité à `slow()`, nous allons créer une fonction wrapper qui ajoute la mise en cache. Comme nous le verrons, cela présente de nombreux avantages.
1212

13-
Voici le code, et les explications suivent:
13+
Voici le code, et les explications suivent :
1414

1515
```js run
1616
function slow(x) {
@@ -29,7 +29,7 @@ function cachingDecorator(func) {
2929

3030
let result = func(x); // sinon appeler func
3131

32-
cache.set(x, result); // et cache (se souvenir) le résultat
32+
cache.set(x, result); // et mettre le résultat en cache
3333
return result;
3434
};
3535
}
@@ -43,30 +43,29 @@ alert( slow(2) ); // slow(2) est mis en cache et le résultat est renvoyé
4343
alert( "Again: " + slow(2) ); // le résultat slow(2) est retourné à partir du cache
4444
```
4545

46-
Dans le code ci-dessus, `cachingDecorator` est un *décorateur*: une fonction spéciale qui prend une autre fonction et modifie son comportement.
46+
Dans le code ci-dessus, `cachingDecorator` est un *décorateur* : une fonction spéciale qui prend une autre fonction et modifie son comportement.
4747

4848
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`.
4949

5050
En séparant la mise en cache du code de la fonction principale, nous simplifions également le code principal.
5151

52-
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:
52+
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 :
5353

5454
![](decorator-makecaching-wrapper.svg)
5555

5656
Depuis un code extérieur, la fonction encapsulée `slow` fait toujours la même chose. Un comportement de mise en cache vient d’être ajouté à son comportement.
5757

58-
Pour résumer, il y a plusieurs avantages à utiliser un `cachingDecorator` distinct au lieu de modifier le code de `slow` lui-même:
58+
Pour résumer, il y a plusieurs avantages à utiliser un `cachingDecorator` distinct au lieu de modifier le code de `slow` lui-même :
5959

6060
- Le `cachingDecorator` est réutilisable. Nous pouvons l'appliquer à une autre fonction.
61-
- 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)
61+
- 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).
6262
- Nous pouvons combiner plusieurs décorateurs si nécessaire (d'autres décorateurs suivront).
6363

64-
6564
## Utilisation de "func.call" pour le contexte
6665

6766
Le décorateur de mise en cache mentionné ci-dessus n'est pas adapté pour travailler avec des méthodes d'objet.
6867

69-
Par exemple, dans le code ci-dessous `worker.slow()` cesse de fonctionner après la décoration:
68+
Par exemple, dans le code ci-dessous `worker.slow()` cesse de fonctionner après la décoration :
7069

7170
```js run
7271
// on ajoutera une fonctionalité de cache à worker.slow
@@ -106,11 +105,11 @@ alert( worker.slow(2) ); // Whoops! Error: Cannot read property 'someMethod' of
106105
*/!*
107106
```
108107

109-
L'erreur se produit dans la ligne `(*)` qui tente d'accéder à `this.someMethod` et échoue. Pouvez-vous voir pourquoi?
108+
L'erreur se produit dans la ligne `(*)` qui tente d'accéder à `this.someMethod` et échoue. Pouvez-vous voir pourquoi ?
110109

111110
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`.
112111

113-
Nous observerions un symptôme similaire si nous essayions d'executer:
112+
Nous observerions un symptôme similaire si nous essayions d'executer :
114113

115114
```js
116115
let func = worker.slow;
@@ -123,23 +122,24 @@ Réparons-le.
123122

124123
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`.
125124

126-
La syntaxe est la suivante:
125+
La syntaxe est la suivante :
127126

128127
```js
129128
func.call(context, arg1, arg2, ...)
130129
```
131130

132131
Il exécute `func` en fournissant `this` comme le premier argument et les suivants en tant qu'arguments.
133132

134-
Pour le dire simplement, ces deux appels font presque la même chose:
133+
Pour le dire simplement, ces deux appels font presque la même chose :
134+
135135
```js
136136
func(1, 2, 3);
137137
func.call(obj, 1, 2, 3)
138138
```
139139

140140
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`.
141141

142-
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`:
142+
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` :
143143

144144
```js run
145145
function sayHi() {
@@ -154,8 +154,7 @@ sayHi.call( user ); // John
154154
sayHi.call( admin ); // Admin
155155
```
156156

157-
Et ici, nous utilisons `call` pour appeler `say` avec le contexte et la phrase donnés:
158-
157+
Et ici, nous utilisons `call` pour appeler `say` avec le contexte et la phrase donnés :
159158

160159
```js run
161160
function say(phrase) {
@@ -204,22 +203,22 @@ alert( worker.slow(2) ); // ça fonctionne, n'appelle pas l'original (mis en cac
204203

205204
Maintenant, tout va bien.
206205

207-
Pour que tout soit clair, voyons plus en détail comment `this` est passé:
206+
Pour que tout soit clair, voyons plus en détail comment `this` est passé :
208207

209208
1. Après la décoration, `worker.slow` est désormais le wrapper `function(x) {...}`.
210209
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).
211-
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. .
210+
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.
212211

213-
## Passer plusieurs arguments
212+
## Passer plusieurs arguments
214213

215214
Rendons maintenant `cachingDecorator` encore plus universel. Jusqu'à présent, il ne travaillait qu'avec des fonctions à un seul argument.
216215

217-
Maintenant, comment mettre en cache la méthode multi-argument `worker.slow`?
216+
Maintenant, comment mettre en cache la méthode multi-argument `worker.slow` ?
218217

219218
```js
220219
let worker = {
221220
slow(min, max) {
222-
return min + max; // tache lourde est supposé
221+
return min + max; // la tâche est supposée lourde
223222
}
224223
};
225224

@@ -229,17 +228,17 @@ worker.slow = cachingDecorator(worker.slow);
229228

230229
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é.
231230

232-
Il y a beaucoup de solutions possibles:
231+
Il y a beaucoup de solutions possibles :
233232

234233
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.
235-
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)`.
234+
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)`.
236235
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.
237236

238237
Pour de nombreuses applications pratiques, la 3ème variante est suffisante, nous allons donc nous y tenir.
239238

240-
Nous devons également transmettre non seulement `x`, mais tous les arguments dans `func.call`. Rappelons que dans une `function()` on peut obtenir un pseudo-tableau de ses arguments comme `arguments`, donc` func.call(this, x) `doit être remplacé par `func.call(this, ...arguments)`.
239+
Nous devons également transmettre non seulement `x`, mais tous les arguments dans `func.call`. Rappelons que dans une `function()` on peut obtenir un pseudo-tableau de ses arguments comme `arguments`, donc `func.call(this, x)` doit être remplacé par `func.call(this, ...arguments)`.
241240

242-
Voici un plus puissant `cachingDecorator` :
241+
Voici un `cachingDecorator` plus puissant :
243242

244243
```js run
245244
let worker = {
@@ -280,7 +279,7 @@ alert( "Again " + worker.slow(3, 5) ); // pareil (mis en cache)
280279

281280
Maintenant, cela fonctionne avec n'importe quel nombre d'arguments (bien que la fonction de hachage doive également être ajustée pour permettre n'importe quel nombre d'arguments. Une façon intéressante de gérer cela sera traitée ci-dessous).
282281

283-
Il y a deux changements:
282+
Il y a deux changements :
284283

285284
- 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.
286285
- Ensuite `(**)` utilise `func.call(this, ...arguments)` pour transmettre le contexte et tous les arguments obtenus par le wrapper (pas seulement le premier) à la fonction d'origine.
@@ -329,7 +328,7 @@ When an external code calls such `wrapper`, it is indistinguishable from the cal
329328

330329
## Emprunter une méthode [#method-borrowing]
331330

332-
Maintenant, apportons une autre amélioration mineure à la fonction de hachage:
331+
Maintenant, apportons une autre amélioration mineure à la fonction de hachage :
333332

334333
```js
335334
function hash(args) {
@@ -339,7 +338,7 @@ function hash(args) {
339338

340339
Pour l'instant, cela ne fonctionne que sur deux arguments. Ce serait mieux s'il pouvait coller un nombre quelconque de `args`.
341340

342-
La solution naturelle serait d'utiliser la méthode [arr.join](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/join):
341+
La solution naturelle serait d'utiliser la méthode [arr.join](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/join) :
343342

344343
```js
345344
function hash(args) {
@@ -349,7 +348,7 @@ function hash(args) {
349348

350349
... 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.
351350

352-
Donc, appeler `join` échouerait, comme on peut le voir ci-dessous:
351+
Donc, appeler `join` échouerait, comme on peut le voir ci-dessous :
353352

354353
```js run
355354
function hash() {
@@ -361,7 +360,7 @@ function hash() {
361360
hash(1, 2);
362361
```
363362

364-
Néanmoins, il existe un moyen simple d’utiliser `join`:
363+
Néanmoins, il existe un moyen simple d’utiliser `join` :
365364

366365
```js run
367366
function hash() {
@@ -377,11 +376,11 @@ L'astuce s'appelle *method borrowing* (empruntage de méthode).
377376

378377
Nous prenons (empruntons) la méthode `join` d'un tableau régulier (`[].join`) et utilisons `[].join.call` pour l'exécuter dans le contexte des `arguments`.
379378

380-
Pourquoi ça marche?
379+
Pourquoi ça marche ?
381380

382381
C'est parce que l'algorithme interne de la méthode native `arr.join(glue)` est très simple.
383382

384-
Tiré de la spécification presque "tel quel":
383+
Tiré de la spécification presque "tel quel" :
385384

386385
1. Soit `glue` le premier argument ou, s’il n’ya pas d’argument, une virgule `","`.
387386
2. Soit `result` une chaîne de caractères vide.
@@ -391,11 +390,11 @@ Tiré de la spécification presque "tel quel":
391390
6. ... Faites-le jusqu'à ce que `this.length` éléments soient collés.
392391
7. Retournez `result`.
393392

394-
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`.
393+
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` (ce n'est pas une coïncidence, de nombreuses méthodes suivent cette pratique). C'est pourquoi cela fonctionne aussi avec `this = arguments`.
395394

396395
## Décorateurs et propriétés fonctionnelles
397396

398-
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 comportait des propriétés, telles que `func.calledCount` ou autre, la fonction décorée ne les fournira pas. Parce que c'est un emballage. Il faut donc faire attention si on les utilise.
397+
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 comportait des propriétés, telles que `func.calledCount` ou autre, la fonction décorée ne les fournira pas. Parce que c'est un wrapper. Il faut donc faire attention si on les utilise.
399398

400399
Dans l'exemple ci-dessus, si la fonction `slow` avait des propriétés, alors `cachingDecorator(slow)` est un wrapper sans elles.
401400

@@ -407,14 +406,14 @@ Il existe un moyen de créer des décorateurs qui conservent l'accès aux propri
407406

408407
*Decorator* est un wrapper autour d'une fonction qui modifie son comportement. Le travail principal est toujours effectué par la fonction.
409408

410-
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!
409+
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 son code !
411410

412-
Pour implémenter `cachingDecorator`, nous avons étudié des méthodes:
411+
Pour implémenter `cachingDecorator`, nous avons étudié les méthodes :
413412

414413
- [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.
415414
- [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.
416415

417-
Le renvoi d'appel, *call forwarding*, est généralement effectué avec `apply`:
416+
Le renvoi d'appel, *call forwarding*, est généralement effectué avec `apply` :
418417

419418
```js
420419
let wrapper = function() {

0 commit comments

Comments
 (0)