Skip to content

Commit 4bd67f3

Browse files
committed
article translate
1 parent 61de0b0 commit 4bd67f3

1 file changed

Lines changed: 63 additions & 63 deletions

File tree

1-js/06-advanced-functions/10-bind/article.md

Lines changed: 63 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -3,114 +3,114 @@ libs:
33

44
---
55

6-
# Function binding
6+
# Привязка контекста к функции
77

8-
When using `setTimeout` with object methods or passing object methods along, there's a known problem: "losing `this`".
8+
При использовании `setTimeout` с методами объекта (или при передаче методов объекта) возникает известная проблема: «потеря `this`».
99

10-
Suddenly, `this` just stops working right. The situation is typical for novice developers, but happens with experienced ones as well.
10+
Внезапно, `this` просто перестает работать правильно. Такая ситуация типична для новичков, но также случается и с опытными разработчиками.
1111

12-
## Losing "this"
12+
## Потеря `this`
1313

14-
We already know that in JavaScript it's easy to lose `this`. Once a method is passed somewhere separately from the object -- `this` is lost.
14+
Мы уже знаем, что в JavaScript легко потерять `this`: когда метод передается где-то отдельно от объекта -- `this` теряется.
1515

16-
Here's how it may happen with `setTimeout`:
16+
Вот как это может произойти с `setTimeout`:
1717

1818
```js run
1919
let user = {
20-
firstName: "John",
20+
firstName: "Вася",
2121
sayHi() {
22-
alert(`Hello, ${this.firstName}!`);
22+
alert(`Привет, ${this.firstName}!`);
2323
}
2424
};
2525

2626
*!*
27-
setTimeout(user.sayHi, 1000); // Hello, undefined!
27+
setTimeout(user.sayHi, 1000); // Привет, undefined!
2828
*/!*
2929
```
3030

31-
As we can see, the output shows not "John" as `this.firstName`, but `undefined`!
31+
При запуске этого кода мы видим, что вызов `this.firstName` возвращает не "Вася", а `undefined`!
3232

33-
That's because `setTimeout` got the function `user.sayHi`, separately from the object. The last line can be rewritten as:
33+
Это произошло потому, что `setTimeout` получил функцию `sayHi`, отдельно от объекта `user` (именно здесь функция и потеряла контекст). То есть последняя строка может быть переписана как:
3434

3535
```js
3636
let f = user.sayHi;
37-
setTimeout(f, 1000); // lost user context
37+
setTimeout(f, 1000); // контекст user потеряли
3838
```
3939

40-
The method `setTimeout` in-browser is a little special: it sets `this=window` for the function call (for Node.js, `this` becomes the timer object, but doesn't really matter here). So for `this.firstName` it tries to get `window.firstName`, which does not exist. In other similar cases as we'll see, usually `this` just becomes `undefined`.
40+
Метод `setTimeout` в браузере имеет особенность: он устанавливает `this=window` для вызова функции (для Node.js `this` становится объектом таймера, но здесь это не имеет значения). Таким образом, для `this.firstName` он пытается получить `window.firstName`, которого не существует. В других подобных случаях, как мы увидим, обычно `this` просто становится `undefined`.
4141

42-
The task is quite typical -- we want to pass an object method somewhere else (here -- to the scheduler) where it will be called. How to make sure that it will be called in the right context?
42+
Задача довольно типичная - мы хотим передать метод объекта куда-то ещё (в этом конкретном случае - в планировщик), где он будет вызван. Как бы сделать так, чтобы он вызывался в правильном контексте?
4343

44-
## Solution 1: a wrapper
44+
## Решение 1: сделать функцию-обёртку
4545

46-
The simplest solution is to use a wrapping function:
46+
Самый простой вариант решения – это обернуть вызов в анонимную функцию, создав замыкание:
4747

4848
```js run
4949
let user = {
50-
firstName: "John",
50+
firstName: "Вася",
5151
sayHi() {
52-
alert(`Hello, ${this.firstName}!`);
52+
alert(`Привет, ${this.firstName}!`);
5353
}
5454
};
5555

5656
*!*
5757
setTimeout(function() {
58-
user.sayHi(); // Hello, John!
58+
user.sayHi(); // Привет, Вася!
5959
}, 1000);
6060
*/!*
6161
```
6262

63-
Now it works, because it receives `user` from the outer lexical environment, and then calls the method normally.
63+
Теперь код работает корректно, так как объект `user` достаётся из замыкания, а затем вызывается его метод `sayHi`.
6464

65-
The same, but shorter:
65+
То же самое, только короче:
6666

6767
```js
68-
setTimeout(() => user.sayHi(), 1000); // Hello, John!
68+
setTimeout(() => user.sayHi(), 1000); // Привет, Вася!
6969
```
7070

71-
Looks fine, but a slight vulnerability appears in our code structure.
72-
73-
What if before `setTimeout` triggers (there's one second delay!) `user` changes value? Then, suddenly, it will call the wrong object!
71+
Выглядит хорошо, но теперь в нашем коде появилась небольшая уязвимость.
7472

73+
Что произойдёт, если до момента срабатывания `setTimeout` (ведь задержка составляет целую секунду!) в переменную `user` будет записано другое значение? Тогда вызов неожиданно будет совсем не тот!
7574

7675
```js run
7776
let user = {
78-
firstName: "John",
77+
firstName: "Вася",
7978
sayHi() {
80-
alert(`Hello, ${this.firstName}!`);
79+
alert(`Привет, ${this.firstName}!`);
8180
}
8281
};
8382

8483
setTimeout(() => user.sayHi(), 1000);
8584

86-
// ...within 1 second
87-
user = { sayHi() { alert("Another user in setTimeout!"); } };
85+
// ...в течение 1 секунды
86+
user = { sayHi() { alert("Другой пользователь в 'setTimeout'!"); } };
8887

89-
// Another user in setTimeout?!?
88+
// Другой пользователь в 'setTimeout'!
9089
```
9190

92-
The next solution guarantees that such thing won't happen.
91+
Следующее решение гарантирует, что такого не случится.
9392

94-
## Solution 2: bind
93+
## Решение 2: привязать контекст с помощью bind
9594

96-
Functions provide a built-in method [bind](mdn:js/Function/bind) that allows to fix `this`.
95+
В современном JavaScript у функций есть встроенный метод [bind](mdn:js/Function/bind), который позволяет исправить `this`.
9796

98-
The basic syntax is:
97+
<!-- The basic syntax is: -->
98+
Базовый синтаксис `bind`:
9999

100100
```js
101-
// more complex syntax will be little later
101+
// полный синтаксис будет представлен немного позже
102102
let boundFunc = func.bind(context);
103-
````
103+
```
104104

105-
The result of `func.bind(context)` is a special function-like "exotic object", that is callable as function and transparently passes the call to `func` setting `this=context`.
105+
Результатом вызова `func.bind(context)` является подобный функции специальный «экзотический объект», который вызывается как функция и прозрачно передает вызов в `func`, при этом устанавливая `this=context`.
106106

107-
In other words, calling `boundFunc` is like `func` with fixed `this`.
107+
Другими словами, вызов `boundFunc` подобен вызову `func` с фиксированным `this`.
108108

109-
For instance, here `funcUser` passes a call to `func` with `this=user`:
109+
Например, здесь `funcUser` передает вызов в `func`, фиксируя `this=user`:
110110

111111
```js run
112112
let user = {
113-
firstName: "John"
113+
firstName: "Вася"
114114
};
115115

116116
function func() {
@@ -119,71 +119,70 @@ function func() {
119119

120120
*!*
121121
let funcUser = func.bind(user);
122-
funcUser(); // John
122+
funcUser(); // Вася
123123
*/!*
124124
```
125125

126-
Here `func.bind(user)` as a "bound variant" of `func`, with fixed `this=user`.
126+
Здесь `func.bind(user)` - это «связанный вариант» `func`, с фиксированным `this=user`.
127127

128-
All arguments are passed to the original `func` "as is", for instance:
128+
Все аргументы передаются исходному методу `func` "как есть", например:
129129

130130
```js run
131131
let user = {
132-
firstName: "John"
132+
firstName: "Вася"
133133
};
134134

135135
function func(phrase) {
136136
alert(phrase + ', ' + this.firstName);
137137
}
138138

139-
// bind this to user
139+
// привязка this к user
140140
let funcUser = func.bind(user);
141141

142142
*!*
143-
funcUser("Hello"); // Hello, John (argument "Hello" is passed, and this=user)
143+
funcUser("Привет"); // Привет, Вася (аргумент "Привет" передан, при этом this = user)
144144
*/!*
145145
```
146146

147-
Now let's try with an object method:
148-
147+
Теперь давайте попробуем с методом объекта:
149148

150149
```js run
151150
let user = {
152-
firstName: "John",
151+
firstName: "Вася",
153152
sayHi() {
154-
alert(`Hello, ${this.firstName}!`);
153+
alert(`Привет, ${this.firstName}!`);
155154
}
156155
};
157156

158157
*!*
159158
let sayHi = user.sayHi.bind(user); // (*)
160159
*/!*
161160

162-
sayHi(); // Hello, John!
161+
sayHi(); // Привет, Вася!
163162

164-
setTimeout(sayHi, 1000); // Hello, John!
163+
setTimeout(sayHi, 1000); // Привет, Вася!
165164
```
166165

167-
In the line `(*)` we take the method `user.sayHi` and bind it to `user`. The `sayHi` is a "bound" function, that can be called alone or passed to `setTimeout` -- doesn't matter, the context will be right.
166+
В строке `(*)` мы берем метод `user.sayHi` и привязываем его к `user`. `SayHi` - это «связанная» функция, которая может быть вызвана отдельно или передана в `setTimeout` - не имеет значения, контекст всегда будет правильным.
168167

169-
Here we can see that arguments are passed "as is", only `this` is fixed by `bind`:
168+
Здесь мы можем видеть, что `bind` исправляет только `this`, а аргументы передаются «как есть»:
170169

171170
```js run
172171
let user = {
173-
firstName: "John",
172+
firstName: "Вася",
174173
say(phrase) {
175174
alert(`${phrase}, ${this.firstName}!`);
176175
}
177176
};
178177

179178
let say = user.say.bind(user);
180179

181-
say("Hello"); // Hello, John ("Hello" argument is passed to say)
182-
say("Bye"); // Bye, John ("Bye" is passed to say)
180+
say("Привет"); // Привет, Вася (аргумент "Привет" передан в функцию "say")
181+
say("Пока"); // Пока, Вася (аргумент "Пока" передан в функцию "say")
183182
```
184183

185-
````smart header="Convenience method: `bindAll`"
186-
If an object has many methods and we plan to actively pass it around, then we could bind them all in a loop:
184+
````smart header="Удобный метод: `bindAll`"
185+
Если у объекта много методов и мы планируем их активно передавать, то можно привязать контекст для них всех в цикле:
187186

188187
```js
189188
for (let key in user) {
@@ -193,11 +192,12 @@ for (let key in user) {
193192
}
194193
```
195194

196-
JavaScript libraries also provide functions for convenient mass binding , e.g. [_.bindAll(obj)](http://lodash.com/docs#bindAll) in lodash.
195+
Некоторые JS-библиотеки предоставляют встроенные функции для удобной массовой привязки контекста, например [_.bindAll(obj)](http://lodash.com/docs#bindAll) в lodash.
197196
````
198197
199-
## Summary
198+
<!-- ## Summary -->
199+
## Итого
200200
201-
Method `func.bind(context, ...args)` returns a "bound variant" of function `func` that fixes the context `this` and first arguments if given.
201+
Метод `func.bind(context, ...args)` возвращает «связанный вариант» функции `func`, который фиксирует контекст `this` и первые аргументы, если они заданы.
202202
203-
Usually we apply `bind` to fix `this` in an object method, so that we can pass it somewhere. For example, to `setTimeout`. There are more reasons to `bind` in the modern development, we'll meet them later.
203+
Обычно мы применяем `bind`, для исправления `this` в методе объекта, чтобы мы могли передать его куда-нибудь. Например, в `setTimeout`. В современной разработке существуют и другие причины для «связывания», мы встретимся с ними позже.

0 commit comments

Comments
 (0)