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
Copy file name to clipboardExpand all lines: 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,7 +6,7 @@ importance: 5
6
6
7
7
Создайте "тормозящий" декоратор `throttle(f, ms)` - который возвращает обёртку, передавая вызов в `f` не более одного раза в `ms` миллисекунд. Те вызовы, которые попадают в период "торможения", игнорируются.
8
8
9
-
**Вариант с`debounce` - если проигнорированный вызов является последним во время "задержки", то он выполняется в конце.**
9
+
**Отличие от`debounce` - если проигнорированный вызов является последним во время "задержки", то он выполняется в конце.**
10
10
11
11
Давайте рассмотрим реальное приложение, чтобы лучше понять это требование и выяснить, откуда оно взято.
Чтобы всё было понятно, давайте посмотрим глубже, как передаётся `this`:
213
213
214
214
1. После *декорации*`worker.slow` становится обёрткой `function (x) { ... }`.
215
-
2. Так что при выполнении `worker.slow(2)` обёртка получает `2` в качестве аргумента, и `this=worker` (это объект перед точкой).
215
+
2. Так что при выполнении `worker.slow(2)` обёртка получает `2` в качестве аргумента, и `this=worker` (так как это объект перед точкой).
216
216
3. Внутри обёртки, если результат еще не кеширован, `func.call(this, x)` передаёт текущий `this` (`=worker`) и текущий аргумент (`=2`) в оригинальную функцию.
217
217
218
-
## Использование нескольких аргументов с "func.apply"
218
+
## Переходим к нескольким аргументам с "func.apply"
219
219
220
220
Теперь давайте сделаем `cachingDecorator` еще более универсальным. До сих пор он работал только с функциями с одним аргументом.
Во-первых, - как использовать оба аргумента `min` и `max` для ключа в коллекции `cache`? Ранее для одного аргумента `x` мы могли просто сохранить результат `cache.set(x, result)` и вызвать `cache.get(x)` чтобы получить его. Но теперь нам нужно запомнить результат для *комбинации аргументов*`(min,max)`. Нативный`Map` принимает только одно значение как ключ.
237
+
Во-первых, - как использовать оба аргумента `min` и `max` для ключа в коллекции `cache`? Ранее для одного аргумента `x` мы могли просто сохранить результат `cache.set(x, result)` и вызвать `cache.get(x)` чтобы получить его. Но теперь нам нужно запомнить результат для *комбинации аргументов*`(min,max)`. Встроенный`Map` принимает только одно значение как ключ.
238
238
239
239
Есть много возможных решений:
240
240
241
-
1. Реализовать новую (или использовать стороннюю) структуру данных типа коллекции, которая которая более универсальна и поддерживает множественные ключи.
241
+
1. Реализовать новую (или использовать стороннюю) структуру данных для коллекции, которая которая более универсальна чем встроенный `Map`, и поддерживает множественные ключи.
242
242
2. Использовать вложенные коллекции: `cache.set(min)` будет `Map` которая хранит пару `(max, result)`. Тогда получить `result` мы можем вызвав `cache.get(min).get(max)`.
243
243
3. Соединить два значения в одно. В нашем конкретном случае мы можем просто использовать строку `"min,max"` как ключ к `Map`. Для гибкости, мы можем позволить передавать *функцию кеширования* в декоратор, которая знает, как сделать одно значение из многих.
Единственная разница в синтаксисе между `call` и `apply` состоит в том, что `call` ожидает список аргументов, в то время как `apply` принимает массивоподобный объект.
287
-
Мы уже знаем оператор расширения `...` из главы <info: rest-parameters-spread-operator>, который может передавать массив (или любой итеративный объект) в виде списка аргументов. Поэтому, если мы используем его с `call`, мы можем достичь почти того же, что и `apply`.
286
+
Единственная разница в синтаксисе между `call` и `apply` состоит в том, что `call` ожидает список аргументов, в то время как `apply` принимает объект-псевдомассив.
287
+
Мы уже знаем оператор расширения `...` из главы <info: rest-parameters-spread-operator>, который может передавать массив (или любой перебираемый объект) в виде списка аргументов. Поэтому, если мы используем его с `call`, мы можем достичь почти того же, что и `apply`.
288
288
Эти два вызова почти эквивалентны:
289
289
290
290
```js
@@ -298,12 +298,12 @@ func.apply(context, args); // тот же эффект
298
298
299
299
Если мы посмотрим более внимательно, то между такими использованиями `call` и` apply` есть небольшая разница.
300
300
301
-
- Оператор расширения `...` позволяет передавать *итеративный* объект `args` в виде списка в `call`.
302
-
- В свою очередь `Apply` принимает только *массивоподобный*объект `args`.
301
+
- Оператор расширения `...` позволяет передавать *перебираемый* объект `args` в виде списка в `call`.
302
+
- В свою очередь `Apply` принимает только *объект-псевдомассив*`args`.
303
303
304
-
Итак, эти вызовы дополняют друг друга. Там, где мы ожидаем итеративность, работает `call`, где мы ожидаем массивоподобный объект, работает `apply`.
304
+
Итак, эти вызовы дополняют друг друга. Там, где мы ожидаем итеративность, работает `call`, где мы ожидаем объект-псевдомассив, работает `apply`.
305
305
306
-
И если `args` является итеративным и похожим на реальный массив, то технически мы могли бы использовать любой из них, но `apply`, вероятно, будет быстрее, потому что это одна операция. Большинство движков JavaScript внутренне оптимизируют его лучше, чем пара `call + spread`.
306
+
И если `args` является перебираемый и похожим на реальный массив, то технически мы могли бы использовать любой из них, но `apply`, вероятно, будет быстрее, потому что это одна операция. Большинство движков JavaScript внутренне оптимизируют его лучше, чем пара `call + spread`.
307
307
308
308
Одним из наиболее важных применений `apply` является передача вызова другой функции, например так:
309
309
@@ -384,7 +384,7 @@ function hash(args) {
384
384
}
385
385
```
386
386
387
-
...К сожалению, это не сработает. Потому что мы вызываем `hash(arguments)`а объект `arguments`является итеративным и массивоподобным, но не реальным массивом.
387
+
...К сожалению, это не сработает. Потому что мы вызываем `hash(arguments)`а объект `arguments` является перебираемым и объектом-псевдомассивом, но не реальным массивом.
388
388
389
389
Таким образом, вызов `join` для него потерпит неудачу, что мы и можем видеть ниже:
390
390
@@ -416,7 +416,7 @@ hash(1, 2);
416
416
417
417
Почему это работает?
418
418
419
-
Это связано с тем, что внутренний алгоритм нативного метода arr.join(glue) очень прост.
419
+
Это связано с тем, что внутренний алгоритм встроенного метода arr.join(glue) очень прост.
420
420
Взято из спецификации практически "как есть":
421
421
422
422
1. Пускай первым аргументом будет `glue` или, в случае отсутствия аргументов, им будет запятая `","`
@@ -440,7 +440,7 @@ hash(1, 2);
440
440
Для реализации `cachingDecorator` мы изучили методы:
441
441
442
442
-[func.call(context, arg1, arg2...)](mdn:js/Function/call) -- вызывает `func` с данным контекстом и аргументами.
443
-
-[func.apply(context, args)](mdn:js/Function/apply) -- вызывает `func` передавая `context` как `this` и массивоподобный`args` как список аргументов.
443
+
-[func.apply(context, args)](mdn:js/Function/apply) -- вызывает `func` передавая `context` как `this` и объект-псевдомассив`args` как список аргументов.
444
444
445
445
В основном *переадресация вызова* выполняется с помощью `apply`:
0 commit comments