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

Исправляет про this в JS #5434

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

gvozdenkov
Copy link
Contributor

Описание

Полностью переписал статью с прозрачным алгоритмом нахождения this по спецификации (с картинками). Плюс отдельно добавил про анархию внешних API.

Чек-лист

  • Текст оформлен согласно руководству по стилю
  • Ссылки на внутренние материалы начинаются со слеша и заканчиваются слэшем либо якорем на заголовок (/css/color/, /tools/json/, /tools/gulp/#kak-ponyat)
  • Ссылки на картинки, видео и демки относительные (images/example.png, demos/example/, ../demos/example/)

@github-actions github-actions bot added js Контент по JavaScript статья Расширенный материал labels Jul 12, 2024
@gvozdenkov gvozdenkov changed the title Исправляет про this в JS Исправляет про this в JS Jul 12, 2024
@HellSquirrel
Copy link
Member

Приветик! Спасибо :)
Мне кажется новый материал лучше выделить в отдельную статью или раздел на практике. Как тебе такая идея?)
Если в статье есть фактические ошибки, давай пробежимся по ним отдельно


Но чтобы лучше понять, что такое `this` и контекст выполнения в JavaScript, нам потребуется зайти издалека.
`this` в JS - это особая переменная, которая определена локально для всех функций (кроме стрелочных). Любая обычная функция вызывается минимум с 1 аргументом - `this`. Но передать его в функцию в виде аргумента нельзя. По умолчанию для обычной функции `this` равен [`undefined`](/js/undefined/). Значение `this` для обычной функции может быть изменено **только в момент вызова** этой функции и зависит от формы и способа её вызова.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this в JS - это особая переменная

Спека и MDN используют понятие ключевое слово (Keyword)

Любая обычная функция вызывается минимум с 1 аргументом - this

MDN предлагает думать о this как о скрытом параметре. По-моему это не совсем тоже самое.

Значение this для обычной функции может быть изменено только в момент вызова этой функции

почему только в момент вызова ?
Function.prototype.bind() создаёт новую функцию и привязывает к ней this

Copy link
Contributor Author

@gvozdenkov gvozdenkov Jul 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Спека и MDN используют понятие ключевое слово (Keyword)
MDN предлагает думать о this как о скрытом параметре. По-моему это не совсем тоже самое.

Согласен

почему только в момент вызова ? Function.prototype.bind() создаёт новую функцию и привязывает к ней this

Хм, тут тонко :) Технически так и написано на MDN, что bind создаёт новую функцию и когда она будет вызвана , то this будет связан с тем, что был в bind

The bind() method of Function instances creates a new function that, when called, calls this function with its this keyword set to the provided value, and a given sequence of arguments preceding any provided when the new function is called.

Тогда так?

this в JS - это ключевое слово. Чтобы не было ассоциации с контекстом выполнения функции (как в других языка), лучше думать о this, как о скрытом параметре обычной (не стрелочной) функции. Но передать этот параметр в функцию в виде аргумента нельзя. По умолчанию, для обычной функции this равен undefined. Значение this для обычной функции задаётся только в момент её вызова. Есть нюанс с bind методом - он создаёт новую функцию и когда эта новая функция будет вызвана, то this будет связан с тем, что было передано в bind

Copy link
Contributor

@vitya-ne vitya-ne Jul 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

лучше думать о this, как о скрытом параметре обычной (не стрелочной) функции. Но передать этот параметр в функцию в виде аргумента нельзя.

Главное не запутать читателя ещё больше )
Если мы предлагаем думать о this как о скрытом параметре, то зачем тут же упоминать только "обычную" функцию?
Разве внутри стрелочной функции обращение к this вызовет ошибку ?

Значение this для обычной функции задаётся только в момент её вызова.

  1. Почему "только" если в следующем предложении описано исключение (использование bind)?
  2. По-моему, не стоит использовать термин "обычная функция". Это только путает. Функция созданная с помощью bind() - обычная ? Если да, почему на неё не распространяется правило привязки при вызове. Если нет, значит у нас уже три вида функций: "обычная", стрелочная и созданная bind().

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Мне кажется тут стоит придерживаться спецификации. Посмотреть можно вот тут https://tc39.es/ecma262/#sec-function-environment-records

This это ключевое слово которое резолвится в некоторое значение. (Упрощенно это ссылка). Куда указывает this определяет https://tc39.es/ecma262/#sec-function-environment-records - лексическая область видимости.
Мне кажется утверждение что эта переменная которая определена для всех функций, кроме стрелочных не очень коректна. This, как мне кажется, это не про функцию а про ее контекст выполнения


В приведённом выше примере вы можете заметить `;` перед анонимной функцией. Дело в том, что существующий механизм автоподстановки точек с запятой (ASI) срабатывает лишь в [определённых случаях](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#automatic_semicolon_insertion), в то время как строка, начинающаяся с `(`, не входит в перечень этих случаев. Поэтому опытные разработчики зачастую добавляют `;` в тех случаях, когда их код может быть скопирован и добавлен в существующий.
Вызывается ли наша функция `logThis` с помощью [`call`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call), [`apply`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) или [`bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)? Если да, то значение `this` будет взято из этих методов:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А как насчёт такого примера:

'use strict';

function logThis() {
  var arrowFunc = () => console.log('this is:', this);
  arrowFunc();
}

var thisArg = { name: 'User' };
var log1 = logThis.bind(thisArg);

log1(); // ?
log1.call(); // ??

var thisArg2 = 42;
log1.call(thisArg2); // ???

thisArg.name = 'Admin';
log1.apply(thisArg2) // ????

thisArg = { x: 0 }
log1.call(thisArg) // ?????

Copy link
Contributor Author

@gvozdenkov gvozdenkov Jul 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А как насчёт такого примера

Хехе, я попался на полседних 2х %) Я кажется ещё чуть глубже осознал JS только что!) Посмотри по комментам к последнему примеру - так?

''use strict';

function logThis() {
  var arrowFunc = () => console.log('this is:', this);
  arrowFunc();
}

var thisArg = { name: 'User' };
var log1 = logThis.bind(thisArg);

// По алгоритму:
// this вунтри функции? да. Обычная функция? нет.
// значит идём в родительское окружение
// Родительское окружение, это обычная функция.
// Как эта функция вызывается? С bind.
// Значит this равно тому, что в bind
log1(); // this is: { name: 'User' }

// По алгоритму:
// this вунтри функции? да. Обычная функция? нет.
// значит идём в родительское окружение
// Родительское окружение, это обычная функция.
// Как эта функция вызывается? С call.
// Значит this должно бы быть равно тому, что в call.
// Но для этой функции уже ранее был прибит гвоздями this - он связан с идентификатором thisArg.
log1.call(); // this is: { name: 'User' }

// По алгоритму:
// this вунтри функции? да. Обычная функция? нет.
// значит идём в родительское окружение
// Родительское окружение, это обычная функция.
// Как эта функция вызывается? С call.
// Значит this должно бы быть равно тому, что в call.
// Но для этой функции уже ранее был прибит гвоздями this - он связан с идентификатором thisArg.
var thisArg2 = 42;
log1.call(thisArg2); // this is: { name: 'User' }

// Этот вызов аналогичен первому вызову log1().
// `this` намертво связан с теми данными в памяти, на которые ссылается идентификатор thisArg
// Мы изменили эти данные, поэтому и вывод Admin
thisArg.name = 'Admin';
log1(); // this is: { name: 'Admin' }

// Этот вызов аналогичен первому вызову log1().
// `this` намертво связан с теми данными в памяти, на которые ссылался идентификатор thisArg
// Выходит, что bind связывает не идентификатор (ссылку на структуру данных в памяти) и this
// Он нацеливает this именно на саму структуру данных.
// И в этом смысле это полная аналогия обычной переменной-идентификатора.
// bind создал как бы переменную-идентификатор и связал её с данными в памяти.
//На эту же память ссылается thisArg.
// То, что мы в процессе перенацелили thisArg куда-то ещё, не изменило то,
// что this так и ссылается на данные в памяти
thisArg = { x: 0 };
log1.call(thisArg); // this is: { name: 'Admin' }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Меня, често говоря, смущают многие коменты:
1.

// Как эта функция вызывается? С bind.

Функция logThis() не вызывается с bind. Она вызывается при вызове log1()

  1. описание поведения при вызове log1.call() как раз противоречит алгоритму, потому что это пока не отражено в схемах и описании статьи.

this намертво связан с теми данными в памяти, на которые ссылался идентификатор thisArg. Выходит, что bind связывает не идентификатор (ссылку на структуру данных в памяти) и this. Он нацеливает this именно на саму структуру данных.

А если мы заменим последний пример вот так:

thisArg = { x: 0 }
var log2 = log1.bind(thisArg)
log2() // ???????

У меня предложение:
Учитывая количество неожиданностей вызванных использованием bind() (точнее поведением bound функций), добавить доку для этого метода. Тогда в этой статье можно ссылаться на материал Доки, а не MDN )

Copy link
Contributor Author

@gvozdenkov gvozdenkov Jul 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vitya-ne Да, выходит в ветке про call, apply, bind нужно уточнить формулировки и добавить несколько комментов и примеров. Спасибо за такую въедливость. Я, кажется, ещё чуть лушче понял js и механизм this:)

Проверь, пожалуйста, такое уточнение по прохождению алгоритма норм? Основной момент - исправить формулировку про call, apply, bind: Применяется ли (а не вызывается) к родительской функции call, apply, bind? Тогда всё становится прозрачно. И да, описание статьи не совсем корректно тогда :)

Я подправил комменты с логикой прохождения по алгоритму. Алгоритм, кажется, верный. Просто можно добавить комментарии про то, как именно this определяется при bind. Поведение, что он "внезапно" изменился, когда мы поменяли thisArg.name более чем предсказуемо, если помнить, что переменные в js не коробочки с данными, а идентификаторы, которые указывают на адреса памяти, где данные реально лежат. Поэтому bind именно связывает this и тот идентификатор. Т.е. this и thisArg начинают ссылаться на одни данные в памяти. Если мы меняем эти данные через thisArg.name, то this автоматически ссылается на обновлённые данные.

Если мы полностью меняем thisArg = { x: 0 } на новые данные, то по мы по сути разрываем связь между thisArg и this. this остался ссылаться на те данные, на которые ссылался раньше thisArg. А thisArg ссылается уже на новую область памяти с другими данными.

Т.е. все манипуляции из примеров ниже не противоречат алгоритму. Они лишь вскрывают нутрянку js про то, как он работает под капотом.

'use strict';

function logThis() {
  var arrowFunc = () => console.log('this is:', this);
  arrowFunc();
}

var thisArg = { name: 'User' };
var log1 = logThis.bind(thisArg);

// 1. this вунтри функции? Да. Это обычная функция? Нет, стрелочная.
// 2. Значит идём в родительское окружение
// 3. Родительское окружение, это обычная функция? Да - logThis.
// 4. Применяется ли к logThis `call`, `apply`, `bind`? Применяется bind
// 5. Значит this связывается с тем идентификатором, который был передан в bind.
log1(); // this is: { name: 'User' }

// 1. this вунтри функции? Да. Это обычная функция? Нет, стрелочная.
// 2. Значит идём в родительское окружение
// 3. Родительское окружение, это обычная функция? Да - logThis.
// 4. Применяется ли к logThis `call`, `apply`, `bind`? Применяется bind
// 5. Значит this связывается с тем идентификатором, который был передан в bind.
// 6. this уже задан, последующий `call` не может его изменить.
log1.call(); // this is: { name: 'User' }

// 1. this вунтри функции? Да. Это обычная функция? Нет, стрелочная.
// 2. Значит идём в родительское окружение
// 3. Родительское окружение, это обычная функция? Да - logThis.
// 4. Применяется ли к logThis `call`, `apply`, `bind`? Применяется bind
// 5. Значит this связывается с тем идентификатором, который был передан в bind.
// 6. this уже задан, последующий `call` не может его изменить.
var thisArg2 = 42;
log1.call(thisArg2); // this is: { name: 'User' }

// Случай аналогичен первому примеру, за 1 исключением
// Мы поменяли данные в памяти, на которые ссылается идентификатор thisArg и this.
// Поэтому this в этом случае и стал другим.
// Но, это всё строго по алгоритму - this связан с тем, чито было передано в 1м bind
// То, что мы потом меняем данные, связанные с thisArg, автоматически меняет и this
thisArg.name = 'Admin';
log1(); // this is: { name: 'Admin' }

// Пример-аналогия, почему это не противоречит алгоритму:
// Идентификатор `a` и `b` ссылаются на одни данные в памяти.
// Если мы меняем данные через идентификатор`a`, то логично, что`b`
// автоматически ссылается на эти новые данные
var a = { name: 'User' };
var b = a; // `b` ссылается на теже данные в памяти, что и `a`
console.log(a); // { name: 'User' };
b.name = 'Admin';
console.log(a); // { name: 'Admin' };
console.log(b); // { name: 'Admin' };
a.name = 'Anonimus';
console.log(a); // { name: 'Anonimus' };
console.log(b); // { name: 'Anonimus' };
a = 42; // `a` ссылается теперь на другой адрес и не связана с `b`
console.log(b); // { name: 'Anonimus' };
b.name = 'Random';
console.log(b); // { name: 'Random' };
console.log(a); // 42

// 1. this вунтри функции? Да. Это обычная функция? Нет, стрелочная.
// 2. Значит идём в родительское окружение
// 3. Родительское окружение, это обычная функция? Да - logThis.
// 4. Применяется ли к logThis `call`, `apply`, `bind`? Применяется bind
// 5. Значит this связывается с тем идентификатором, который был передан в bind - thisArg
// 6. Перед вызовом `log1.call(thisArg)` данные, на которые указывает thisArg
// были изменены: `thisArg.name = 'Admin';`
// Но this всё равно ссылается ровно на те данные, на которые ссылается thisArg.
// Поэтому вывод`this is: { name: 'Admin' }`
// 6. Переопределение thisArg и вызов `call` вообще никак не влияет на this.
// This уже связан с другими данными.
// Мы просто теперь потеряли вообще всякую возможность до них дотянуться,
// перенацелив thisArg на новые данные`thisArg = { x: 0 }`
thisArg = { x: 0 };
log1.call(thisArg); // this is: { name: 'Admin' }

// 1. this вунтри функции? Да. Это обычная функция? Нет, стрелочная.
// 2. Значит идём в родительское окружение
// 3. Родительское окружение, это обычная функция? Да - logThis.
// 4. Применяется ли к logThis `call`, `apply`, `bind`? Применяется bind
// 5. Значит this связывается с тем идентификатором, который был передан в bind - thisArg
// 6. Перед вызовом `log1.call(thisArg)` данные, на которые указывает thisArg
// были изменены: `thisArg.name = 'Admin';`
// Но this всё равно ссылается ровно на те данные, на которые ссылается thisArg.
// Поэтому вывод`this is: { name: 'Admin' }`
// 6. Переопределение thisArg и вызов `bind` вообще никак не влияет на this.
// This уже связан с другими данными.Перенацелить this невозможно.
// Мы просто теперь потеряли вообще всякую возможность до них дотянуться,
// перенацелив thisArg на новые данные`thisArg = { x: 0 }`
thisArg = { x: 0 };
var log2 = log1.bind(thisArg);
log2(); // this is: { name: 'Admin' }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Спасибо, за развёрнутый ответ )
С моей стороны это не совсем "въедливость" )
Я просто своими примерами намекаю что идея алгоритма, как мне кажется, не очень удачна.
Потому что появляется много исключений:

  1. В какой момент мы проходим по алгоритму? если при вызове функции, то .bind() это лишне, так как нам на самом деле нужно понять это bound-функция или нет. А как это сделать если функция создана где-то в другом месте?
  2. "Применяется ли к logThis call, apply, bind"
    c call и apply функция вызывается, тут как ни крути не объединишь с bind().
  3. "This уже связан с другими данными.Перенацелить this невозможно"
    Опять же, вот пример из серии "его биортим не лез в алгоритм":
function Point(x, y) {
  this.x = x;
  this.y = y;
  console.log(this);
}

const superThis = { z: 3 };
const YAxisPoint = Point.bind(superThis, 1);

const a = new YAxisPoint(2); // ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: Вдохновивишись, я начал работать над ответом на вопрос из этой статьи "Для чего используется метод Function.prototype.bind()?" )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vitya-ne Такс, ещё чуть лучше пойму js %) По примеру выше кажется понял, как блоксхему алгоритма переделать. Хочется впихнуть таки, чтобы не осталось непоняток про this:)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

погляди (если интересно) и поревьювь (если хочешь) мой мерж про .bind()

@gvozdenkov
Copy link
Contributor Author

Приветик! Спасибо :) Мне кажется новый материал лучше выделить в отдельную статью или раздел на практике. Как тебе такая идея?) Если в статье есть фактические ошибки, давай пробежимся по ним отдельно

Текущая статься в целом не врёт.

Но заголовок статьи уже вводит в заблуждение. Статья запутывает отсылкой к контексту выполнения и даёт набор частных примеров чему this равняется в разных случаях. И после прочтения остаётся осадочек о том, что JS малопредсказуем, что this загадочный и таинственный, что он куда-то может теряться и прочий набор мифов. Я сам this только недавно начал понимать не как какую-то непонятную магию JS ^)

Поэтому я бы настаивал на замене статьи. Чтобы не было ассоциаций с контекстом и был внятный и предсказуемый алгоритм чему this равняется. Без магии, без частностей. А цельное и простое (кажется) объяснение this

title: "`this`: контекст выполнения функций"
description: "Про контекст и `this` часто спрашивают на собеседованиях. Ответим подробно и разберёмся в нюансах."
title: "В поисках `this`"
description: "Хочешь знать чему `this` равняется - проверь, как функция вызывается."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Учитывая поведение стрелочных функций и функций созданных bind(), дескрипшн содержит не совсем верное утверждение.

@TatianaFokina TatianaFokina added the улучшение Доработка существующего label Jul 16, 2024
@gvozdenkov
Copy link
Contributor Author

@HellSquirrel @vitya-ne Изрядно переписал по итогу всех обсуждений. Посмотрите, пожалуйста. Теперь, вроде бы, всё укладывается в алгоритм.

  1. Уточнил описание. Как и Какая функция вызывается. Кажется правильной формулировкой. Если не брать глобальный контекст, потому что с практической точки зрения this там никому не нужна. То получается this зависит от того где он находится - стрелочная, обычная функция или функция, полученная с помощью bind. И от того как функция вызывается - просто, call, apply, new, dot нотация
  2. Расписал на примерах кажущиеся ислкючения, почему кажется, что this меняется. Хотя не меняется, если понимать под this ссылку. Могут измениться данные по этой сслыке, но не сама ссылка.
  3. Уточнил шаги блоксхемы, чтобы нагляднее было

@HellSquirrel
Copy link
Member

я немного позже посмотрю :) можешь пока зарезолвить конфликт?)

@gvozdenkov
Copy link
Contributor Author

я немного позже посмотрю :) можешь пока зарезолвить конфликт?)

Получится посмотреть? А то зависла статья что-то

Copy link
Member

@HellSquirrel HellSquirrel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Привет, ты очень круто переработал эту статью. Я сейчас очень медленно ревьюю, извини что статья зависла
Мне очень понравились схемы. Я добавила несколько замечаний.
Еще пробегись пожалуйста по терминологии
JavaScript, Node.js вроде бы ничего больше не нашла :)


Выполнить что-то в JS можно 4 способами:
❗ Все примеры ниже будут для [_строгого режима_](/js/use-strict/). В не строгом режиме значения `this` будет местами отличаться. Строгий режим автоматически влючён для режима `module`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можешь поделиться ссылочкой на термин "режим модуля"?
Мне кажется это не совсем режим (его нельзя включить - выключить) Вот спека https://tc39.es/ecma262/#sec-ecmascript-language-scripts-and-modules

- вызвав метод объекта;
- использовав функцию-конструктор;
- непрямым вызовом функции.
### `this` и Global Environment
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Возможно лучше использовать термин глобальное окружение

## Функция

Первый и самый простой способ выполнить что-то — вызвать функцию.
Самый простой (и бесполезный с практической точки зрения) случай, когда `this` находится в глобальном окружении. Т.е. `this` находится не внутри функции, а на "самом верхнем уровне":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Давай попробуем использовать более точное "ключевое слово this". Если кратко - this это ссылка не нечто. Довольно сложно сказать где это нечто находится однако легко сказать где используется ключевое слово.
Подробности вот тут https://tc39.es/ecma262/#sec-environment-records

### Глобальный объект
- Если `module`, то `this` равен `undefined`
- Если `script`, `this` ссылается на Global Object, но хост среда может изменять это по своему усмотрению:
- В браузере поведение `this` не меняется. `this` ссылается на Global Object, который равен объекту `window`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- В браузере поведение `this` не меняется. `this` ссылается на Global Object, который равен объекту `window`
- В браузере поведение `this` не меняется. `this` ссылается на Global Object, на него же ссылается `window`

- Если `module`, то `this` равен `undefined`
- Если `script`, `this` ссылается на Global Object, но хост среда может изменять это по своему усмотрению:
- В браузере поведение `this` не меняется. `this` ссылается на Global Object, который равен объекту `window`
- Хост среда `nodejs` изменяет `this` по своей спецификации и устанавливает его равным пустому объекту `{}`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Хост среда `nodejs` изменяет `this` по своей спецификации и устанавливает его равным пустому объекту `{}`
- Хост среда `Node.js` изменяет `this` по своей спецификации и устанавливает его равным пустому объекту `{}`


Если мы запускаем JS-код в браузере, то глобальным объектом будет `window`. Если мы запускаем код в Node-окружении, то `global`.
### `this` и Arrow Function
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### `this` и Arrow Function
### `this` в стрелочных функциях

whatsThis()
// true
```
Если к родительской обычной функции применяется метод [`bind(thisArg, ...args)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind), то возвращется новая функция. При вызове эта новая функция вызывает исходную функцию с аргументами `...args` и 'нацеливает' `this` на те данные, на которые указывает идентификатор `thisArg`. Если к новой функции (которая возвращается после `.bind()`) применить `call`, `apply` или снова `bind`, то это не изменит `this`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Если к родительской обычной функции применяется метод [`bind(thisArg, ...args)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind), то возвращется новая функция. При вызове эта новая функция вызывает исходную функцию с аргументами `...args` и 'нацеливает' `this` на те данные, на которые указывает идентификатор `thisArg`. Если к новой функции (которая возвращается после `.bind()`) применить `call`, `apply` или снова `bind`, то это не изменит `this`.
Если к родительской обычной функции применяется метод [`bind(thisArg, ...args)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind), то возвращется новая функция. При вызове эта новая функция вызывает исходную функцию с аргументами `...args` и связывает `this` с идентификатором `thisArg`. Если к новой функции (которая возвращается после `.bind()`) применить `call`, `apply` или снова `bind`, то это не изменит привязки `this`.


## Метод объекта
![this and bind without new](./images/bind-no-new-this.png)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Давай тут добавим более подробное описание. Вот тут у нас есть гайд по описанию картиночек https://github.com/doka-guide/content/blob/main/docs/styleguide.md#%D0%BA%D0%B0%D1%80%D1%82%D0%B8%D0%BD%D0%BA%D0%B8

```

Обратите внимание, что `this` определяется в момент вызова функции. Если записать метод объекта в переменную и вызвать её, значение `this` изменится.
Есть важный нюас про переменные в js. Ассоциация с коробочкой и данными не очень подходит для js. Лучше думать, что переменная содержит ссылку на адрес в памяти, где данные действительно лежат:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Есть важный нюас про переменные в js. Ассоциация с коробочкой и данными не очень подходит для js. Лучше думать, что переменная содержит ссылку на адрес в памяти, где данные действительно лежат:
Ассоциация с коробочкой и данными не очень подходит для описания переменных в JavaScript. Лучше думать, что переменная содержит ссылку на адрес в памяти, где данные действительно лежат:

Минорно - это тоже не очень точная модель представления переменных. Подробнее можно посмотреть вот тут https://doka.guide/tools/trivial-memory-model/

```
Поэтому пример ниже не противоречит алгоритму, а лишь показывает суть того, чем являются переменные в js:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Поэтому пример ниже не противоречит алгоритму, а лишь показывает суть того, чем являются переменные в js:
Поэтому пример ниже не противоречит алгоритму, а лишь показывает суть того, чем являются переменные в JavaScript:

Кроме этого важно понимать что это поведение не распространяется на все типы в языке. Для объектов это работает именно так. Давай попробуем обойти эту тему. Мне кажется ее будет сложно раскрыть в рамках этой статьи

Copy link

github-actions bot commented Oct 2, 2024

Превью контента из 076ae6f опубликовано.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
js Контент по JavaScript статья Расширенный материал улучшение Доработка существующего
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants