Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function binding #203

Merged
merged 9 commits into from
Sep 30, 2021
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
The answer: `null`.
Відповідь: `null`.


```js run
Expand All @@ -13,6 +13,6 @@ let user = {
user.g();
```

The context of a bound function is hard-fixed. There's just no way to further change it.
Контекст прив’язаної функції жорстко-фіксований. Немає способу змінити це в подальшому.

So even while we run `user.g()`, the original function is called with `this=null`.
Так чином в той час як ми запускаємо `user.g()`, функція `f` викликається з `this=null`.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ importance: 5

---

# Bound function as a method
# Прив’язана функція як метод

What will be the output?
Що виведе функція?

```js
function f() {
Expand Down
10 changes: 5 additions & 5 deletions 1-js/06-advanced-functions/10-bind/3-second-bind/solution.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
The answer: **John**.
Відповідь: **Іван**.

```js run no-beautify
function f() {
alert(this.name);
}

f = f.bind( {name: "John"} ).bind( {name: "Pete"} );
f = f.bind( {name: "Іван"} ).bind( {name: "Христя"} );

f(); // John
f(); // Іван
```

The exotic [bound function](https://tc39.github.io/ecma262/#sec-bound-function-exotic-objects) object returned by `f.bind(...)` remembers the context (and arguments if provided) only at creation time.
Екзотичний об’єкт [прив’язаної функції](https://tc39.github.io/ecma262/#sec-bound-function-exotic-objects) повертається від `f.bind(...)`, що запам’ятовує контекст (та аргументи, якщо передані) тільки під час створення.

A function cannot be re-bound.
Функція не може бути переприв’язана.
8 changes: 4 additions & 4 deletions 1-js/06-advanced-functions/10-bind/3-second-bind/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ importance: 5

---

# Second bind
# Друга прив’язка

Can we change `this` by additional binding?
Чи можемо ми змінити `this` за допомогою додаткового прив’язування?

What will be the output?
Який результат буде виведено?

```js no-beautify
function f() {
alert(this.name);
}

f = f.bind( {name: "John"} ).bind( {name: "Ann" } );
f = f.bind( {name: "Іван"} ).bind( {name: "Христя" } );

f();
```
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
The answer: `undefined`.
Відповідь: `undefined`.

The result of `bind` is another object. It does not have the `test` property.
Результатом `bind` є інший об’єкт. Він не містить властивість `test`.

Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ importance: 5

---

# Function property after bind
# Властивість функції після прив’язки

There's a value in the property of a function. Will it change after `bind`? Why, or why not?
Функції присвоєна властивість зі значенням. Чи зміниться вона після `bind`? Чому?

```js run
function sayHi() {
Expand All @@ -14,10 +14,10 @@ sayHi.test = 5;

*!*
let bound = sayHi.bind({
name: "John"
name: "Іван"
});

alert( bound.test ); // what will be the output? why?
alert( bound.test ); // що виведе функція? Чому?
*/!*
```

22 changes: 11 additions & 11 deletions 1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@

The error occurs because `ask` gets functions `loginOk/loginFail` without the object.
Помилка виникає тому що `askPassword` отримує функції `loginOk/loginFail` без об’єкту.

When it calls them, they naturally assume `this=undefined`.
Коли вона викликає їх, їх контекст втрачено `this=undefined`.

Let's `bind` the context:
Спробуємо використати `bind`, щоб прив’язати контекст:

```js run
function askPassword(ok, fail) {
let password = prompt("Password?", '');
let password = prompt("Пароль?", '');
if (password == "rockstar") ok();
else fail();
}

let user = {
name: 'John',
name: 'Іван',

loginOk() {
alert(`${this.name} logged in`);
alert(`${this.name} увійшов`);
},

loginFail() {
alert(`${this.name} failed to log in`);
alert(`${this.name} виконав невдалу спробу входу`);
},

};
Expand All @@ -30,14 +30,14 @@ askPassword(user.loginOk.bind(user), user.loginFail.bind(user));
*/!*
```

Now it works.
Тепер це працює.

An alternative solution could be:
Альтернативне рішення могло б бути:
```js
//...
askPassword(() => user.loginOk(), () => user.loginFail());
```

Usually that also works and looks good.
Зазвичай це також працює та чудово виглядає.

It's a bit less reliable though in more complex situations where `user` variable might change *after* `askPassword` is called, but *before* the visitor answers and calls `() => user.loginOk()`.
Це менш найдіно, так як в більш складних ситуаціях змінна `user` може змінитися *після* виклику `askPassword`, але *перед* викликом `() => user.loginOk()`.
16 changes: 8 additions & 8 deletions 1-js/06-advanced-functions/10-bind/5-question-use-bind/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,30 @@ importance: 5

---

# Fix a function that loses "this"
# Виправте функцію, яка втратила 'this'

The call to `askPassword()` in the code below should check the password and then call `user.loginOk/loginFail` depending on the answer.
Виклик `askPassword()` в коді наведеному нижче повинен перевіряти пароль та викликати `user.loginOk/loginFail` в залежності від відповіді.

But it leads to an error. Why?
Але виконання коду призводить до помилки. Чому?

Fix the highlighted line for everything to start working right (other lines are not to be changed).
Виправте виділений рядок, щоб код запрацював правильно (інші рядки не мають бути змінені).

```js run
function askPassword(ok, fail) {
let password = prompt("Password?", '');
let password = prompt("Пароль?", '');
if (password == "rockstar") ok();
else fail();
}

let user = {
name: 'John',
name: 'Іван',

loginOk() {
alert(`${this.name} logged in`);
alert(`${this.name} увійшов`);
},

loginFail() {
alert(`${this.name} failed to log in`);
alert(`${this.name} виконав невдалу спробу входу`);
},

};
Expand Down
6 changes: 3 additions & 3 deletions 1-js/06-advanced-functions/10-bind/6-ask-partial/solution.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@


1. Either use a wrapper function, an arrow to be concise:
1. Або використовуйте стрілкову функцію як функцію-обгортку для короткого запису:

```js
askPassword(() => user.login(true), () => user.login(false));
```

Now it gets `user` from outer variables and runs it the normal way.
Тепер `user` отримується з зовнішніх змінних та код виконується правильно.

2. Or create a partial function from `user.login` that uses `user` as the context and has the correct first argument:
2. Або створіть частково застосовану функцію `user.login`, що використовує `user` як контекст та має правильний аргумент:


```js
Expand Down
16 changes: 8 additions & 8 deletions 1-js/06-advanced-functions/10-bind/6-ask-partial/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,26 @@ importance: 5

---

# Partial application for login
# Часткове застосування для логіну

The task is a little more complex variant of <info:task/question-use-bind>.
Задача трохи складніша ніж <info:task/question-use-bind>.

The `user` object was modified. Now instead of two functions `loginOk/loginFail`, it has a single function `user.login(true/false)`.
Об’єкт `user` був змінений. Тепер замість двох функцій `loginOk/loginFail`, він має одну функцію `user.login(true/false)`.

What should we pass `askPassword` in the code below, so that it calls `user.login(true)` as `ok` and `user.login(false)` as `fail`?
Що ми маємо передати `askPassword` в коді нижче, щоб вона викликала `user.login(true)` при `ok` та `user.login(false)` при `fail`?

```js
function askPassword(ok, fail) {
let password = prompt("Password?", '');
let password = prompt("Пароль?", '');
if (password == "rockstar") ok();
else fail();
}

let user = {
name: 'John',
name: 'Іван',

login(result) {
alert( this.name + (result ? ' logged in' : ' failed to log in') );
alert( this.name + (result ? ' увійшов' : ' виконав невдалу спробу входу') );
}
};

Expand All @@ -30,5 +30,5 @@ askPassword(?, ?); // ?
*/!*
```

Your changes should only modify the highlighted fragment.
Вносіть зміни тільки у виділений рядок.

Loading