HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <p>JavaScript - асинхронный язык программирования. Из-за этого функции часто вызываются как колбеки других функций. Особенно много этого в браузере, где колбек на колбеке и колбеком погоняет. Пока мы работали с простыми функциями, это не вызывало никаких затруднений, но все меняется при использовании методов.</p>
1 <p>JavaScript - асинхронный язык программирования. Из-за этого функции часто вызываются как колбеки других функций. Особенно много этого в браузере, где колбек на колбеке и колбеком погоняет. Пока мы работали с простыми функциями, это не вызывало никаких затруднений, но все меняется при использовании методов.</p>
2 <p><em>На этом этапе мы еще не работали с асинхронностью, но это не должно помешать понять идею. В двух словах: функция setTimeout принимает на вход функцию и время, после которого ее надо вызвать. Когда приходит время, она это делает. В общем-то и всё.</em></p>
2 <p><em>На этом этапе мы еще не работали с асинхронностью, но это не должно помешать понять идею. В двух словах: функция setTimeout принимает на вход функцию и время, после которого ее надо вызвать. Когда приходит время, она это делает. В общем-то и всё.</em></p>
3 <p>Попробуйте запустить такой код:</p>
3 <p>Попробуйте запустить такой код:</p>
4 <p>Теперь тот же самый код мы хотим вызвать не сразу, а через секунду. Для этого используем функцию setTimeout(), которая вызывает переданную функцию через указанное количество времени.</p>
4 <p>Теперь тот же самый код мы хотим вызвать не сразу, а через секунду. Для этого используем функцию setTimeout(), которая вызывает переданную функцию через указанное количество времени.</p>
5 <p>Этот код выдаст hello, undefined. Почему? Потому что внутрь setTimeout() мы передали не объект printer, а функцию print() без объекта. А значит эта функция потеряла связь с самим объектом и ее this больше не указывает на объект. Вот так можно проиллюстрировать то, что происходит:</p>
5 <p>Этот код выдаст hello, undefined. Почему? Потому что внутрь setTimeout() мы передали не объект printer, а функцию print() без объекта. А значит эта функция потеряла связь с самим объектом и ее this больше не указывает на объект. Вот так можно проиллюстрировать то, что происходит:</p>
6 <p>Если контекста нет, то this оказывается равным пустому объекту, если мы говорим про обычные функции.</p>
6 <p>Если контекста нет, то this оказывается равным пустому объекту, если мы говорим про обычные функции.</p>
7 <p>Такое поведение часто нежелательно. Практически всегда, когда передается метод, подразумевается, что он будет вызван в контексте того объекта, которому он принадлежит. Существует несколько способов добиться такого поведения. Самый простой - обернуть функцию в функцию, пока мы вызываем функцию.</p>
7 <p>Такое поведение часто нежелательно. Практически всегда, когда передается метод, подразумевается, что он будет вызван в контексте того объекта, которому он принадлежит. Существует несколько способов добиться такого поведения. Самый простой - обернуть функцию в функцию, пока мы вызываем функцию.</p>
8 <p>Это распространенное решение, которое заодно помогает захватить внешние переменные, когда они нужны для вызова:</p>
8 <p>Это распространенное решение, которое заодно помогает захватить внешние переменные, когда они нужны для вызова:</p>
9 <h2>Связывание (Bind)</h2>
9 <h2>Связывание (Bind)</h2>
10 <p>Другой способ - использование метода bind() (переводится как связать). Метод bind() доступен у функций, и в его задачу входит связывание функции с каким-то контекстом. Результатом выполнения bind() будет<strong>новая функция</strong>, работающая, как и исходная функция, но с привязанным к ней контекстом.</p>
10 <p>Другой способ - использование метода bind() (переводится как связать). Метод bind() доступен у функций, и в его задачу входит связывание функции с каким-то контекстом. Результатом выполнения bind() будет<strong>новая функция</strong>, работающая, как и исходная функция, но с привязанным к ней контекстом.</p>
11 <p>Связанная функция сливается со своим контекстом "намертво". Больше this не поменяется.</p>
11 <p>Связанная функция сливается со своим контекстом "намертво". Больше this не поменяется.</p>
12 <p>Кроме контекста, bind() принимает на вход параметры, которые нужны функции. Причем не сразу все, а любую их часть. bind() подставит их в новую функцию (ту, что вернется из метода bind()) "частично". Эта техника называется "частичное применение функции". Так можно сразу применить нужные аргументы:</p>
12 <p>Кроме контекста, bind() принимает на вход параметры, которые нужны функции. Причем не сразу все, а любую их часть. bind() подставит их в новую функцию (ту, что вернется из метода bind()) "частично". Эта техника называется "частичное применение функции". Так можно сразу применить нужные аргументы:</p>
13 <p>Подход с bind() был популярен до появления стрелочных функций, сейчас его используют нечасто. Стрелочные функции проще для понимания и используются повсеместно.</p>
13 <p>Подход с bind() был популярен до появления стрелочных функций, сейчас его используют нечасто. Стрелочные функции проще для понимания и используются повсеместно.</p>
14 <h2>Apply &amp; Call</h2>
14 <h2>Apply &amp; Call</h2>
15 <p>bind() полезен там, где привязка контекста и вызов функции происходят в разных местах и, как правило, в разное время. Мы встретимся с таким кодом, когда перейдем к асинхронности в JavaScript.</p>
15 <p>bind() полезен там, где привязка контекста и вызов функции происходят в разных местах и, как правило, в разное время. Мы встретимся с таким кодом, когда перейдем к асинхронности в JavaScript.</p>
16 <p>Иногда вызов функций, использующих внутри себя this, происходит сразу вместе с привязкой контекста. Это можно сделать напрямую, сразу же вызвав функцию, возвращаемую bind: ...bind(/* контекст */)():</p>
16 <p>Иногда вызов функций, использующих внутри себя this, происходит сразу вместе с привязкой контекста. Это можно сделать напрямую, сразу же вызвав функцию, возвращаемую bind: ...bind(/* контекст */)():</p>
17 <p>а можно использовать специально созданные для этого функции apply() и call():</p>
17 <p>а можно использовать специально созданные для этого функции apply() и call():</p>
18 <p>Эти функции внутри себя делают две вещи: меняют контекст и сразу же производят вызов функции. Разница лишь в том, как они работают с аргументами этих функций: apply() - принимает аргументы в виде массива вторым параметром, а call() ждёт на вход позиционные аргументы.</p>
18 <p>Эти функции внутри себя делают две вещи: меняют контекст и сразу же производят вызов функции. Разница лишь в том, как они работают с аргументами этих функций: apply() - принимает аргументы в виде массива вторым параметром, а call() ждёт на вход позиционные аргументы.</p>
19 <p>Эти функции позволяют делать довольно необычные вещи, например так:</p>
19 <p>Эти функции позволяют делать довольно необычные вещи, например так:</p>
20 <p>Вызов выше просто демонстрация, с практической точки зрения он мало полезен. Реальное использование call() и apply() проявляется в связке контекста с функциями из прототипов. Об этом поговорим в следующих уроках.</p>
20 <p>Вызов выше просто демонстрация, с практической точки зрения он мало полезен. Реальное использование call() и apply() проявляется в связке контекста с функциями из прототипов. Об этом поговорим в следующих уроках.</p>