Форум программистов, компьютерный форум, киберфорум
JavaScript для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
10 / 10 / 1
Регистрация: 20.08.2016
Сообщений: 245

Декораторы и переадресация вызова

17.12.2025, 05:03. Показов 523. Ответов 7
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Привет, объясните пожалуйста работу примеров из учебника простыми словами. Несколько раз перечитал и всё равно не понимаю.

Почему в первом примере

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function slow(x) {
  // здесь могут быть ресурсоёмкие вычисления
  alert(`Called with ${x}`);
  return x;
}
 
function cachingDecorator(func) {
  let cache = new Map();
 
  return function(x) {
    if (cache.has(x)) {    // если кеш содержит такой x,
      return cache.get(x); // читаем из него результат
    }
 
    let result = func(x); // иначе, вызываем функцию
 
    cache.set(x, result); // и кешируем (запоминаем) результат
    return result;
  };
}
 
slow = cachingDecorator(slow);
 
alert( slow(1) ); // slow(1) кешируем
alert( "Again: " + slow(1) ); // возвращаем из кеша
 
alert( slow(2) ); // slow(2) кешируем
alert( "Again: " + slow(2) ); // возвращаем из кеша
всё происходит нормально, как и задумывалось, а во втором нет?

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// сделаем worker.slow кеширующим
let worker = {
  someMethod() {
    return 1;
  },
 
  slow(x) {
    // здесь может быть страшно тяжёлая задача для процессора
    alert("Called with " + x);
    return x * this.someMethod(); // (*)
  }
};
 
// тот же код, что и выше
function cachingDecorator(func) {
  let cache = new Map();
  return function(x) {
    if (cache.has(x)) {
      return cache.get(x);
    }
    let result = func(x); // (**)
    cache.set(x, result);
    return result;
  };
}
 
alert( worker.slow(1) ); // оригинальный метод работает
 
worker.slow = cachingDecorator(worker.slow); // теперь сделаем его кеширующим
 
alert( worker.slow(2) ); // Ой! Ошибка: не удаётся прочитать свойство 'someMethod' из 'undefined'
Почему при выполнении этого кода

JavaScript
1
return x * this.someMethod(); // (*)
и запуске

JavaScript
1
worker.slow = cachingDecorator(worker.slow);
происходит ошибка, ведь мы так же сделали ссылку на тот же объект worker?

Почему внутри обёртки переменная this оказывается равной undefined?

Почему контекст вызова внутри обёртки не привязан к объекту worker?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
17.12.2025, 05:03
Ответы с готовыми решениями:

Тема: Декораторы
function slow(x) { alert(`Called with ${x}`); return x; } function...

Приоритет выполнения функций (декораторы)
Доброго времени суток, есть такой кусок кода, не могу понять как связаны декораторы cacheDecorator...

Переадресация в зависимости от выпадающего списка
Есть список: <form method="post" name="blablabla"> <select name="menu" size="1"> ...

7
 Аватар для voraa
1261 / 1226 / 180
Регистрация: 21.01.2024
Сообщений: 5,655
17.12.2025, 07:13
Цитата Сообщение от sozdatel Посмотреть сообщение
Почему контекст вызова внутри обёртки не привязан к объекту worker?
Потому, что вы его отвязываете, когда передаете функцию
JavaScript
1
cachingDecorator(worker.slow);
Вот посмотрите
JavaScript
1
2
3
4
5
6
7
8
9
const obj = {
    a: 1,
    method () { console.log (this)},
}
 
obj.method ();  // вызов с контекстом this = obj
const f = obj.method;
 
f(); // вызов без контекста this = undefined / window
const f = obj.method; //присваивает функцию, но не контекст
]cachingDecorator(worker.slow); // передает функцию но не контекст.

Надо передавать функцию с контекстом с помощью bind

JavaScript
1
2
3
4
5
6
7
8
9
const obj = {
    a: 1,
    method () { console.log (this)},
}
 
obj.method ();  // вызов с контекстом this = obj
const f = obj.method.bind(obj);
 
f(); // вызов с контекстом this = obj
Надо
JavaScript
1
worker.slow = cachingDecorator(worker.slow.bind(worker));
1
Эксперт JSЭксперт HTML/CSS
 Аватар для krvsa
3833 / 1677 / 431
Регистрация: 14.03.2022
Сообщений: 4,228
17.12.2025, 09:29
Цитата Сообщение от sozdatel Посмотреть сообщение
ведь мы так же сделали ссылку на тот же объект worker?
Ссылка на объект worker делается вот так

JavaScript
1
const o = worker;
А у тебя происходит "заимствование функции". И, как следствие, потеря контекста...
0
10 / 10 / 1
Регистрация: 20.08.2016
Сообщений: 245
17.12.2025, 14:11  [ТС]
Цитата Сообщение от voraa Посмотреть сообщение
JavaScript
1
2
3
4
5
6
7
const obj = {
    a: 1,
    method () { console.log (this)},
}
obj.method ();  // вызов с контекстом this = obj
const f = obj.method;
f(); // вызов без контекста this = undefined / window

Цитата Сообщение от voraa Посмотреть сообщение
JavaScript
1
const f = obj.method; //присваивает функцию, но не контекст
Можете написать, почему таким образом не присваивается контекст для f? Ведь мы этой строкой привязали f к методу объекта, к которому мы имеем доступ?
0
Эксперт JSЭксперт HTML/CSS
 Аватар для krvsa
3833 / 1677 / 431
Регистрация: 14.03.2022
Сообщений: 4,228
17.12.2025, 14:26
Цитата Сообщение от sozdatel Посмотреть сообщение
Можете написать, почему таким образом не присваивается контекст для f?
Так нет никакого "присваивания контекста". Таким присваиванием ты просто "заимствовал метод".
Такое можно реализовать если использовать bin(), call() или apply()

Вот что про такое пишут в учебнике https://learn.javascript.ru/bind

Добавлено через 2 минуты
Цитата Сообщение от sozdatel Посмотреть сообщение
Ведь мы этой строкой привязали f к методу объекта, к которому мы имеем доступ?
Это не привязка.
Это получение ссылки на функцию.
А вот в каком контексте эта функция будет вызываться - это еще вопрос.

Например, если установить эту функцию в качестве обработчика на некую кнопку - this в ней будет указывать на кнопку.
1
10 / 10 / 1
Регистрация: 20.08.2016
Сообщений: 245
17.12.2025, 15:11  [ТС]
И ещё, почему в коде ниже строка
JavaScript
1
 let result = func.call(this, x);
привязывает контекст worker.slow к worker, а не к cachingDecorator?
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
let worker = {
  someMethod() {
    return 1;
  },
 
  slow(x) {
    alert("Called with " + x);
    return x * this.someMethod(); // (*)
  }
};
 
function cachingDecorator(func) {
  let cache = new Map();
  return function(x) {
    if (cache.has(x)) {
      return cache.get(x);
    }
    let result = func.call(this, x); // теперь 'this' передаётся правильно
    cache.set(x, result);
    return result;
  };
}
 
worker.slow = cachingDecorator(worker.slow); // теперь сделаем её кеширующей
 
alert( worker.slow(2) ); // работает
alert( worker.slow(2) ); // работает, не вызывая первоначальную функцию (кешируется).
0
 Аватар для voraa
1261 / 1226 / 180
Регистрация: 21.01.2024
Сообщений: 5,655
17.12.2025, 15:37
Цитата Сообщение от sozdatel Посмотреть сообщение
Ведь мы этой строкой привязали f к методу объекта, к которому мы имеем доступ?
Мы ничего не привязываем.
Если по простому
this передается в функцию, когда она вызывается как метод. <object>.<function>(); Вот то, что стоит перед . то передается, как this. Если ничего не стоит (нет в вызове <object>. а просто <function>() ) то ничего не передается, и this будет window / undefined)
При использовании методов call, apply и bind мы принудительно указываем, что передать в this

Когда мы пишем
JavaScript
1
const f = obj.method;
Мы просто в переменную f записываем ссылку на какую то функцию. Про то, что это метод какого то объекта, и тем более какого объекта, f ничего не знает. Просто какая то функция.

Цитата Сообщение от sozdatel Посмотреть сообщение
И ещё, почему в коде ниже строка
 let result = func.call(this, x);
привязывает контекст worker.slow к worker, а не к cachingDecorator?
Потому, что this в этом случае то, что пришло в функцию
JavaScript
1
2
3
4
5
6
7
8
function(x) {
    if (cache.has(x)) {
      return cache.get(x);
    }
    let result = func.call(this, x); // теперь 'this' передаётся правильно
    cache.set(x, result);
    return result;
  };
при ее вызове. А вызывалась она, как worker.slow(2). Значит this внутри нее будет worker.
1
Эксперт JSЭксперт HTML/CSS
 Аватар для krvsa
3833 / 1677 / 431
Регистрация: 14.03.2022
Сообщений: 4,228
17.12.2025, 15:52
Цитата Сообщение от sozdatel Посмотреть сообщение
почему в коде ниже строка
JavaScript
1
 let result = func.call(this, x);
привязывает контекст worker.slow к worker, а не к cachingDecorator?
Так cachingDecorator это функция, которая вернет функцию, назовем ее хешированной. Которая в свою очередь будет замкнута на переменную cache.
На этом роль функции cachingDecorator завершена и она нам более не интересна.
А вот хешированную функцию присваивают свойству slow объекта worker. Т.о. имеем хешированный метод объекта.
Этот самый хешированный метод вызывают в контексте объекта worker.
Цитата Сообщение от sozdatel Посмотреть сообщение
JavaScript
1
let result = func.call(this, x);
Т.ч. теперь this тут ссылается на объект worker.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
17.12.2025, 15:52
Помогаю со студенческими работами здесь

Переадресация страницы через Х секунд без доступа к head
Добрый день! Есть страница index.php, которая грузит контент через ряд инклудов. Схема примерно...

переадресация при нажатие клавишь
то есть при нажатие ctrl+y происходит переадресация на другой сайт

Переадресация при нажатии кнопки вход
Помогите пожалуйста)нужно написать скрипт, который при нажатии вход будут отправлять на другую...

Переадресация с одного сайта на другой
Доброго времени суток уважаемыые форумчани, мне необходимо сделать переадресацию. Чтобы при заходе...

ajax переадресация
Здравствуйте, делаю запрос через ajax на авторизацию, как в случае успешной авторизации сделать...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Логарифм записывается как: (x-2)log(x^2+2) - означает логарифм (x^2+2) по основанию (x-2). Унарный минус обозначается как ! */ #include <iostream> #include <stack> #include <cctype>. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru