You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
**In chapter 01-06-09 call apply decorators**
Some of sentences were correct, but they were "unnatural" in Ukrainian and make understanding more difficult.
Copy file name to clipboardExpand all lines: 1-js/06-advanced-functions/09-call-apply-decorators/article.md
+27-27Lines changed: 27 additions & 27 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,7 +6,7 @@ JavaScript дає виняткову гнучкість при роботі з
6
6
7
7
Скажімо, у нас є функція `slow(x)`, яка виконує ресурсоємкі операції, але її результати стабільні. Іншими словами, для того ж `x` вона завжди повертає той же результат.
8
8
9
-
Якщо функція часто викликається, ми можемо кешувати (запам’ятати) її результати, щоб не витрачати час на перерахування.
9
+
Якщо функція часто викликається, ми можемо кешувати (запам’ятати) її результати, щоб не витрачати час на повторне обчислення.
10
10
11
11
Але замість того, щоб додати цю функціональність в `slow()` ми створимо функцію-обгортку, що додає кешування. Як ми побачимо, існує багато переваг такого підходу.
12
12
@@ -23,7 +23,7 @@ function cachingDecorator(func) {
23
23
let cache =newMap();
24
24
25
25
returnfunction(x) {
26
-
if (cache.has(x)) { // якщо такий ключ є в кеш
26
+
if (cache.has(x)) { // якщо такий ключ є в кеші
27
27
returncache.get(x); // прочитайти результат з нього
28
28
}
29
29
@@ -63,7 +63,7 @@ alert( "Again: " + slow(2) ); // slow(2) result returned from cache
63
63
64
64
## Використання "func.call" для контексту
65
65
66
-
Кешуючий декоратор, згаданий вище, не підходить для роботи з методами об’єкта.
66
+
Написаний вище кешуючий декоратор не підходить для роботи з методами об’єкта.
67
67
68
68
Наприклад, у коді нижче `worker.slow()` перестане працювати після використання декоратора:
69
69
@@ -138,7 +138,7 @@ func.call(obj, 1, 2, 3)
138
138
139
139
Обидва вони викликаюсь `func` з аргументами `1`, `2` і `3`. Єдина відмінність полягає в тому, що `func.call` також встановлює `this` рівним `obj`.
140
140
141
-
Як приклад, у коді нижче ми викликаємо `sayHi` в контексті різних об’єктів: `sayHi.call(user)` викликає `sayHi`, передаючи `this=user`, а на наступних рядках встановлюється `this=admin`:
141
+
Як приклад, у коді нижче ми викликаємо `sayHi`, передаючи їй в якості контексту (в якості `this`) різні об'єкти: `sayHi.call(user)` викликає `sayHi`, передаючи `this=user`, а на наступних рядках встановлюється `this=admin`:
Щоб все було зрозуміло, давайте подивимося більш глибоко, як `this` передається:
207
207
208
-
1. Після декорування `worker.slow`стає функцією обгортки`function (x) { ... }`.
208
+
1. Після декорування в значення `worker.slow`було присвоєно функцію декоратор`function (x) { ... }`.
209
209
2. Отже, коли `worker.slow(2)` виконується, обгортка отримує `2` в якості аргумента і `this=worker` (це об’єкт перед крапкою).
210
210
3. Всередині обгортки, якщо результат ще не кешований, `func.call(this, x)` передає поточний `this` (`=worker`) та поточний аргумент (`=2`) до оригінального методу.
211
211
@@ -226,15 +226,15 @@ let worker = {
226
226
worker.slow=cachingDecorator(worker.slow);
227
227
```
228
228
229
-
Раніше, для одного аргументу `x`, ми могли просто `cache.set(x, result)`, щоб зберегти результат та `cache.get(x)`, щоб отримати його. Але тепер нам потрібно пам’ятати результат для *комбінації аргументів*`(min,max)`. Вбудований `Map` приймає лише одне значення як ключ.
229
+
Раніше, для одного аргументу `x`, ми могли написати просто `cache.set(x, result)`, щоб зберегти результат та `cache.get(x)`, щоб отримати його. Але тепер нам потрібно пам’ятати результат для *комбінації аргументів*`(min,max)`. Вбудований `Map` приймає лише одне значення як ключ.
230
230
231
231
Є багато можливих рішень:
232
232
233
-
1. Впровадити нову (або скористайтеся сторонньою) map-подібну структуру даних, яка більш універсальна і дозволяє використовувати декілька ключів.
233
+
1. Впровадити нову (або взяти готову сторонню) map-подібну структуру даних, яка більш універсальна і дозволяє використовувати декілька ключів.
234
234
2. Використати вкладені коллекції: `cache.set(min)` буде `Map`, що зберігає пару `(max, result)`. Таким чином, ми можемо отримати `result` як `cache.get(min).get(max)`.
235
-
3. З’єднати два значення в одне. У нашому конкретному випадку ми можемо просто використовувати рядок `"min,max"` як ключ `Map`. Для гнучкості ми можемо забезпечити *функція хешування* для декоратора, що знає, як зробити одне значення з багатьох.
235
+
3. З’єднати два значення в одне. У нашому конкретному випадку ми можемо просто використовувати рядок `"min,max"` як ключ `Map`. Для гнучкості ми можемо забезпечити *функцію хешування* для декоратора, що знає, як зробити одне значення з багатьох.
236
236
237
-
Для багатьох практичних застосунків, 3-й варіант досить хороший, тому ми будемо дотримуватися його.
237
+
На практиці частіше всього використовують 3-й варіант, тому ми будемо дотримуватися його.
238
238
239
239
Також ми повинні передати не просто `x`, але всі аргументи в `func.call`. Давайте пригадаємо, що в `function()` ми можемо отримати псевдо-масив її аргументів, як `arguments`, тому `func.call(this, x)` слід замінити на `func.call(this, ...arguments)`.
240
240
@@ -281,8 +281,8 @@ alert( "Знову " + worker.slow(3, 5) ); // те ж саме значення
281
281
282
282
Є дві зміни:
283
283
284
-
- В рядку `(*)` викликається `hash`, щоб створити одну ключ з `arguments`. Тут ми використовуємо просту функцію "приєднання", яка перетворює аргументи `(3, 5)` у ключ `"3,5"`. Більш складні випадки можуть потребувати інших функцій хешування.
285
-
- Потім `(**)` використовує `func.call(this, ...arguments)`, щоб передати як контекст, так і всі аргументи (а не тільки перший) обгортки до оригінальної функції.
284
+
- В рядку `(*)` викликається `hash`, щоб створити один ключ з `arguments`. Тут ми використовуємо просту функцію "приєднання", яка перетворює аргументи `(3, 5)` у ключ `"3,5"`. Більш складні випадки можуть потребувати інших функцій хешування.
285
+
- Потім `(**)` використовує `func.call(this, ...arguments)`, щоб передати як контекст, так і всі аргументи (а не тільки перший) з обгортки до оригінальної функції.
Вони виконують той самий виклик `func` з даним контекстом та аргументами.
308
+
Вони виконують той самий виклик `func` з вручну вказаним їм контекстом (`this`) та аргументами.
309
309
310
310
Є тільки тонка різниця щодо `args`:
311
311
312
-
- Оператор розширення `...` дозволяє передати *ітерований*`args`як список до `call`.
312
+
- Оператор розширення `...` дозволяє передати *ітеровуваний*`args`у вигляді окремих елементів до `call`.
313
313
-`apply` приймає лише *псевдо-масив*`args`.
314
314
315
-
... і для об’єктів, які є як ітерованими, так і псевдо-масивами, а так само як і справжніми масивами, ми можемо використовувати будь-який з цих методів, але`apply`, мабуть, буде швидше, тому що більшість рушіїв JavaScript внутрішньо оптимізують його краще.
315
+
...А для об'єктів, які є одночасно і ітеровуваними, і псевдомасивами чи й справжніми масивами, ми можемо використовувати будь-який з цих методів. Але`apply`, мабуть, буде працювати швидше, бо більшість рушіїв JavaScript внутрішньо оптимізовують його краще.
316
316
317
-
Передача всіх аргументів разом з контекстом до іншої функції називається *переадресація виклику*.
317
+
Передача всіх аргументів разом з контекстом до іншої функції називається *переадресація виклику* (call forwarding).
318
318
319
319
Це найпростіша її форма:
320
320
@@ -336,24 +336,24 @@ function hash(args) {
336
336
}
337
337
```
338
338
339
-
Зараз вона працює лише на двох аргументах. Було б краще, якби вона могла зкріпити будь-яку кількість `args`.
339
+
Зараз вона працює лише для двох аргументів. Було б краще, якби вона могла зклеїти будь-яку кількість `args`.
340
340
341
-
Звичайним рішенням буде використати [arr.join](mdn:js/Array/join) метод:
341
+
Перше, що приходить в голову - це використати метод [arr.join](mdn:js/Array/join):
342
342
343
343
```js
344
344
functionhash(args) {
345
345
returnargs.join();
346
346
}
347
347
```
348
348
349
-
...На жаль, це не буде працювати. Тому що ми викликаємо `hash(arguments)`, а об’єкт `arguments` є як ітерованим, так і псевдо-масивом, але не справжнім масивом.
349
+
...На жаль, це не буде працювати. Ми викликаємо `hash(arguments)`, а об’єкт `arguments` є одночасно як ітеровуваним, так і псевдо-масивом, але не справжнім масивом.
350
350
351
351
Отже, виклик `join` на цьому об’єкті буде призводити до помилки, що ми бачимо нижче:
352
352
353
353
```js run
354
354
functionhash() {
355
355
*!*
356
-
alert( arguments.join() ); //Помилка: arguments.join не є функцією
356
+
alert( arguments.join() ); //TypeError: arguments.join is not a function
357
357
*/!*
358
358
}
359
359
@@ -374,7 +374,7 @@ hash(1, 2);
374
374
375
375
Трюк називається *запозичення методу*.
376
376
377
-
Ми беремо (запозичуємо) метод приєднання від звичайного масиву (`[].join`) і використовуємо `[].join.call` щоб запустити його в контексті `arguments`.
377
+
Ми беремо (запозичуємо) метод приєднання від звичайного масиву (`[].join`) і використовуємо `[].join.call` щоб запустити його з `arguments` в якості його `this`.
378
378
379
379
Чому це працює?
380
380
@@ -394,24 +394,24 @@ hash(1, 2);
394
394
395
395
## Декоратори та функціональні властивості
396
396
397
-
Як правило, можна безпечно замінити функцію або метод декоратором, за винятком однієї дрібниці. Якщо оригінальна функція мала властивості в собі, як наприклад `func.calledCount` або щось інше, то декорований об’єкт не буде надавати доступ до них. Тому що це обгортка. Тому потрібно бути обережним, якщо використовує її.
397
+
Як правило, можна безпечно замінити функцію або метод декоратором, за винятком однієї дрібниці. Якщо оригінальна функція мала властивості в собі, як наприклад `func.calledCount` або щось інше, то декорований об’єкт не буде надавати доступ до них. Бо це обгортка. Тому потрібно бути обережним, якщо використовуєте її.
398
398
399
-
Наприклад, у прикладі вище, якщо `slow` функція мала будь-які властивості в собі, то `cachingDecorator(slow)`-- це обгортка без них.
399
+
Наприклад, у прикладі вище, якщо `slow` функція мала б будь-які властивості в собі, то `cachingDecorator(slow)`повернув би обгортку без них.
400
400
401
-
Деякі декоратори можуть забезпечити свої власні властивості.Наприклад, декоратор може підрахувати, скільки разів функція була викликана, і скільки часу це зайняло, і виставляти цю інформацію за допомогою властивостей обгортки.
401
+
Деякі декоратори можуть забезпечити свої власні властивості.Наприклад, декоратор може підрахувати, скільки разів функція була викликана, і скільки часу це зайняло, і виставляти цю інформацію за допомогою властивостей обгортки.
402
402
403
403
Існує спосіб створити декоратори, які зберігають доступ до властивостей функцій, але це вимагає використання спеціального об’єкту `Proxy`, щоб обернути функцію. Ми обговоримо це пізніше у статті <info:proxy#proxy-apply>.
404
404
405
405
## Підсумки
406
406
407
-
*Декоратор* -- це обгортка навколо функції, яка змінює її поведінку. Основна робота все ще виконується за допомогою функції.
407
+
*Декоратор* -- це обгортка навколо функції, яка повторює її поведінку. Основна робота все ще виконується за допомогою функції.
408
408
409
409
Декоратори можна розглядати як "особливості" або "аспекти", які можна додати до функції. Ми можемо додати один або додати багато декораторів. І все це, не змінюючи коду оригінальної функції!
410
410
411
411
Для реалізації `cachingDecorator`, ми вивчали методи:
412
412
413
-
-[func.call(context, arg1, arg2...)](mdn:js/Function/call) -- викликає `func` з заданим контекстом та аргументами.
414
-
-[func.apply(context, args)](mdn:js/Function/apply) -- викликає `func`передаючи `context` як `this` та псевдо-масив `args` як список аргументів.
413
+
-[func.call(context, arg1, arg2...)](mdn:js/Function/call) -- викликає `func` з вручним указанням контексту та з списком аргументів.
414
+
-[func.apply(context, args)](mdn:js/Function/apply) -- викликає `func`з вручним указанням контексту та псевдо-масив (або й звичайний масив)`args` як список аргументів.
415
415
416
416
Зазвичай *переадресація викликів* виконується завдяки `apply`:
417
417
@@ -421,6 +421,6 @@ let wrapper = function() {
421
421
};
422
422
```
423
423
424
-
Ми також бачили приклад *запозичення методу*, коли ми беремо метод з об’єкта та `call` його в контексті іншого об’єкта.Досить поширено брати методи масиву та застосувати їх до`arguments`. Альтернативою є використання об’єкта, який є справжнім масивом, за допомогою rest оператору.
424
+
Ми також бачили приклад *запозичення методу*, коли ми беремо метод з об’єкта та викликаємо (`call`), встановлюючи йому в якості this інший об'єкт. Досить поширено брати методи масиву та застосувати до них`arguments`. Альтернативою є використання об’єкта, який є справжнім масивом, за допомогою rest оператору.
425
425
426
426
На практиці є багато декораторів для різних задач. Перевірте, наскільки добре ви засвоїли їх, вирішивши завдання цієї глави.
0 commit comments