Javascript this: this — JavaScript | MDN

«это» странно: Понимание JavaScript «это» Ключевое слово

Линтон Йе

Последнее обновление:

оглавление

  • это не только для классов это определяется во время выполнения
  • Вызов функции с принимающим объектом
  • Новое ключевое слово
  • Другие способы изменить это во время выполнения
  • вызов и применение
  • bind
  • bind всегда выигрывает
  • this в функциях обратного вызова
  • то и это
  • this в стрелочных функциях
  • this в стрелочных функциях не может быть изменено
  • Quiz
  • Назад к компонентам класса React
  • Резюме

Однако его поведение может показаться очень странным, особенно если вы знакомы с подобными конструкциями в других языках, например, this в Java или self в Python 1 .

Возьмите этот компонент класса React 2 в качестве примера:

 class MyComponent extends React. Component {
  конструктор () {
    супер()
    это.состояние = {количество: 0}
  }
  обработатьклик() {
    this.setState({ count: this.state.count + 1})
  }
  оказывать() {
    вернуть 
  }
}
 

Этот код отображает счетчик на кнопке. Выглядит нормально, правда? Но если вы нажмете кнопку, вы получите ошибку (попробуйте в этой песочнице):

 TypeError: Не удается прочитать свойство «количество» неопределенного
 

Это означает, что значение this.state в handleClick равно undefined . Но почему? Разве мы не установили его на { count: 0 } в конструкторе?

Теперь, если вы добавите console.log(this) в handleClick , вы увидите значение this :

 Window {...}
 

Почему? Разве не должен быть

текущим экземпляром класса? Разве не handleClick метод экземпляра класса?

Это странно!

В этом посте давайте кратко рассмотрим, как этот работает в JavaScript.

Целевая аудитория

В этой статье предполагается базовое понимание JavaScript. Вы также найдете его полезным, если вы знакомы с другими языками, такими как Java или Python.

В таких языках, как Java, ключевое слово this имеет смысл только внутри класса. Но в JavaScript мы можем использовать его практически везде:

 // Используйте `this` на верхнем уровне, также известном как глобальный контекст
console.log(это)
 

Теперь откройте консоль JavaScript и введите приведенный выше код. Что вы получили?

При использовании на верхнем уровне, также известном как глобальный контекст, значением this является объект

Window . Это значение по умолчанию this 3 .

Мы также можем использовать ключевое слово this в функции, например:

 function printThis() {
  console.log(это)
}
 

Что будет напечатано, если мы вызовем эту функцию? Текущий экземпляр. .. функции? Объект Окно ?

Короткий ответ: мы еще не знаем!

Более длинный ответ:

Значение этого внутри функции зависит от способа вызова функции.

Разве это не странно? Отсюда больше всего путаницы.

Продолжайте читать 👇.

Вызов функции с принимающим объектом

Попробуйте ввести в консоли следующий код:

 function printThis() {
  console.log(это)
}
распечатать это ()
 

В этом коде мы получаем значение по умолчанию this , Window

object 4 .

Теперь попробуйте следующий код:

 // определяем функцию как свойство obj
пусть объект = {
  printThis: функция () {
    console.log(это)
  },
}
obj.printThis ()
 

Получаем объект, в котором определена функция! Хм, это интересно.

Но в этом есть смысл, верно? Это позволяет функции легко получить доступ к свойствам объекта, например:

 let car = {
  марка: «Тесла»,
  модель: '3',
  печать: функция () {
    console. log(`Производитель: ${this.make}, Модель: ${this.model}`)
  },
}
car.print()
 

Получится:

 Марка: Tesla, Модель: 3
 

Но это не конец истории! Что, если мы назначим функцию переменной и назовем ее так:

 let print = car.print
// вызов функции без принимающего объекта
Распечатать()
 

Получим:

 Марка: не определено, Модель: не определено
 

Хм… Функция забывает об объекте, в котором она определена? этот странный!

Как я уже сказал,

Значение этого внутри функции зависит от того, как вызывается функция.

Поскольку мы вызываем функцию print без принимающего объекта, хотя функция определена внутри объекта автомобиля, значение это Окно , значение по умолчанию. У него нет свойств make и model .

Теперь небольшая викторина. Как вы думаете, что напечатает следующий код?

 функция печати () {
  console. log(`Производитель: ${this.make}, Модель: ${this.model}`)
}
пусть грузовик = {
  марка: «Тесла»,
  модель: «Кибергрузовик»,
}
грузовик.print = печать
грузовик.print()
 

A:

Марка: не определено, Модель: не определено

B:

Марка: Tesla, Модель: Cybertruck

C:

Марка: Tesla, Модель: undefined

D:

Ни один из вышеперечисленных как вызывается функция, НЕ где функция определена.

Разве это не странно?

новое ключевое слово

Мы также можем вызвать функцию с новым ключевое слово:

 функция Автомобиль(марка, модель) {
  это.сделать = сделать
  эта.модель = модель
}
пусть автомобиль = новый автомобиль ('Tesla', '3')
console.log(машина)
 

Получим:

 Автомобиль {марка: "Tesla", модель: "3"}
 

При вызове функции с ключевым словом new мы получим новый объект. Значение this внутри этой функции равно новому объекту.

Следующий код эквивалентен, но в формате класса:

 class Car {
  конструктор (производитель, модель) {
    // `this` это новый объект
    это.сделать = сделать
    эта.модель = модель
  }
}
пусть автомобиль = новый автомобиль ('Tesla', '3')
console.log(машина)
 

На самом деле class в JavaScript — это просто синтаксический сахар. Под капотом это просто функция.

До сих пор я показал вам, что значение это зависит от того, как вызывается функция:

  • Вызывали ли мы функцию с принимающим объектом? то есть obj.print() или просто print() ?
  • Мы вызвали функцию с новым ключевым словом ?

Но это далеко не полная картина! Оказывается, мы можем изменить значение это в функции к тому, что мы хотим — нам даже не нужно использовать принимающий объект.

вызов и применение

Мы можем вызвать любую функцию, используя вызов или

применение , чтобы указать значение this :

 function anyFunction() {
  console. log(это)
}
anyFunction.call({ msg: 'независимо' })
// Вывод: Объект { msg: "что угодно" }
anyFunction.apply({ msg: 'независимо' })
// Вывод: Объект { msg: "что угодно" }
 

bind

Метод bind возвращает функцию, которую мы можем вызывать так же, как исходную функцию. Но мы можем быть уверены, что значение это всегда то, что мы хотим.

 функция printThis() {
  console.log(это)
}
let print = printThis.bind({ msg: 'Я могу быть любым объектом, который вы хотите!' })
Распечатать()
 

Вывод:

 Object { msg: "Я могу быть любым объектом, который вы хотите!"}
 

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

bind всегда выигрывает

Стоит отметить, что пока функция связана, это внутри функции остается привязанным значением. Его больше нельзя изменить с помощью , вызова или , применения или даже принимающего объекта.

 функция printThis() {
  console.log(это)
}
letboundFun = printThis.bind(`Я связан! Вы не можете изменить мое "это"!`!)
boundFun.call('ха-ха')
// Вывод: я связан! Вы не можете изменить мое "это"!
boundFun.apply('лала')
// Вывод: я связан! Вы не можете изменить мое "это"!
пусть объект = {}
obj.printThis = связанное удовольствие
obj.printThis ()
// Вывод: я связан! Вы не можете изменить мое "это"!
 

В JavaScript мы можем передавать функцию как любое другое значение. Функция обычно называется

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

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

В приведенном ниже коде значение отличается в каждой функции обратного вызова:

 let colors = ['красный', 'зеленый', 'синий']
пусть кнопка = документ. getElementById('кнопка')
button.addEventListener('щелчок', функция () {
  // Внутри callback-функции 1: обработчик события
  // `this` является ссылкой на элемент, по которому щелкнули
  colors.forEach (функция () {
    // Внутри callback-функции 2
    // `это` значение по умолчанию, `Окно`
  })
})
 

этот и that

В приведенном выше коде, если мы хотим использовать значение this во второй функции обратного вызова, нам нужно сохранить его значение в переменной внешней функции.

На самом деле это становится обычным шаблоном:

 button.addEventListener('click', function () {
  пусть это = это
  colors.forEach (функция () {
    console.log(это)
    // Вывод: кнопка
  })
})
 

ES6 представляет стрелочные функции, которые позволяют нам использовать более простой синтаксис для определения функции, т. е. стрелку => вместо функции ключевое слово :

 пусть весело = () => {
  console. log("Я в функции стрелки!")
}
 

Какое значение это внутри стрелочной функции? Это та же история, что и в «нормальной» функции?

Нет! В стрелочной функции поведение и полностью противоположно!

В стрелочной функции значение этого зависит от , где функция определена, а НЕ от того, как функция вызывается!

Значение this в стрелочной функции такое же, как и в закрывающем блоке функции. Итак, нам больше не нужен танец то-то в стрелочных функциях:

 button.addEventListener('click', function () {
  // пусть это = это // ==> Больше не нужно!
  console.log(это)
  // Вывод: кнопка
  colors.forEach(() => {
    // В стрелочной функции this равно значению this во внешней области видимости
    console.log(это)
    // Вывод: кнопка
  })
})
 

это в стрелочных функциях не может быть изменено

Опять же, значение это в стрелочной функции зависит от , где определена функция. Поэтому его нельзя изменить во время выполнения!

Это означает, что ни один из bind , call или apply не влияет на функции стрелок. Предоставленное это значение просто игнорируется.

 пусть arrowFun = () => {
  console.log(это)
}
arrowFun.call('Измени это!')
// Вывод: окно
arrowFun.apply('Измени это!')
// Вывод: окно
пусть boundArrowFun = arrowFun.bind('Изменить!')
границаСтрелкаFun()
// Вывод: окно
 

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

Вам может быть интересно узнать о новом ключевом слове . Изменит ли это значение на ?

Ответ НЕТ! На самом деле, вы даже не можете вызвать стрелочную функцию с new .

 пусть arrowFun = () => {
  console.log(это)
}
новая стрелкаFun()
// Uncaught TypeError: arrowFun не является конструктором
 

Тест

А как насчет быстрого теста? Каков результат кода ниже?

 пусть автомобиль = {
  марка: «Тесла»,
  модель: '3',
  напечатать: () => {
    console. log(`Производитель: ${this.make}, Модель: ${this.model}`)
  },
}
car.print()
 

A:

Make: Undefined, модель: не определено

B:

Make: Tesla, Модель: 3

C:

Make: Tesla, модель: не определено

D.

Ошибка типа

Давайте вернемся к примеру компонента класса, который я показал вам в начале. Теперь вы понимаете, почему мы получаем сообщение об ошибке, когда пользователь нажимает кнопку? Почему значение этого равно Window вместо объекта экземпляра внутри handleClick ?

 класс MyComponent расширяет React.Component {
  конструктор () {
    супер()
    это.состояние = {количество: 0}
  }
  обработатьклик() {
    this.setState({ count: this.state.count + 1})
  }
  оказывать() {
    вернуть 
  }
}
 

Что из следующего НЕ является причиной ошибки?

A:

Функция «handleClick» передается кнопке и вызывается без принимающего объекта.

B:

Значение по умолчанию «this» внутри handleClick равно «Window».

C:

Значение «this» всегда равно «Window» внутри класса.

Как исправить ошибку в вышеупомянутом компоненте класса? Как бы мы убедились, что значение это в handleClick текущий экземпляр класса вместо Window ? Другими словами, есть ли способ явно установить значение для этого ?

Ответ: bind :

 class MyComponent extends React.Component {
  конструктор () {
    супер()
    это.состояние = {количество: 0}
    // `this` в конструкторе всегда является только что созданным новым объектом.
    this. handleClick = this.handleClick.bind(это)
  }
  обработатьклик() {
    this.setState({ количество: количество + 1})
  }
  оказывать() {
    вернуть 
  }
}
 

Еще одно более чистое решение IMO — использовать функцию стрелки:

 class MyComponent extends React.Component {
  конструктор () {
    супер()
    это.состояние = {количество: 0}
  }
  // Определяем handleClick как стрелочную функцию
  handleClick = () => {
    // `this` равно значению окружающего блока.
    // В данном случае это экземпляр объекта.
    this.setState({ count: this.state.count + 1})
  }
  оказывать() {
    вернуть 
  }
}
 

Хорошо, выше показано, как это работает в JavaScript. Вам все еще кажется это странным? ИМО чувствует себя намного лучше, если мы понимаем правила под капотом. Вот резюме:

  • этот предназначен не только для занятий. Его можно использовать глобально, в функции или в классе.
  • В «обычных» функциях значение этого зависит от того, как вызывается во время выполнения.
    • Мы можем изменить значение на этот с помощью вызова , применить или связать .
  • В стрелочных функциях и совершенно противоположны. Значение этого зависит от , где функция определена.
    • Значение этого НЕ МОЖЕТ быть изменено во время выполнения.
  • В компоненте класса React мы можем использовать bind или стрелочную функцию, чтобы гарантировать, что значение this будет объектом экземпляра класса. Это делает поведение этот больше соответствует другим языкам.

Чтобы узнать больше, ознакомьтесь с этой статьей MDN и этим ответом StackOverflow (более 1300 голосов!).


  1. Здесь моя собственная история. Я так долго боролся с и в JavaScript. Это именно из-за моего опыта работы с Java — у меня с самого начала была неправильная ментальная модель. ↩
  2. Я знаю, в наши дни мы больше не пишем столько компонентов класса в React. Но все же полезно понимать их, поскольку вы обычно видите их в устаревшем коде. Не у всех есть время переписать все компоненты класса как функциональные компоненты.↩
  3. Поскольку JavaScript может работать в среде, отличной от веб-браузера, существует специальное ключевое слово globalThis , которое указывает на Window или другое значение в зависимости от среды. undefined или другие значения в строгом режиме.↩

Посещений:

0

Надеюсь, эта статья окажется для вас полезной!

Одна из моих целей на 2021 год — написать больше постов, которых будет 9.0089 полезные , интерактивные и развлекательные . Хотите получать ранние предварительные просмотры будущих сообщений? Зарегистрируйтесь ниже. Никакого спама, отпишитесь в любое время.

Вам также может понравиться

React useRef Hook By Example: A Complete Guide

Обновлено:

react

useRef — это встроенный React Hook. Для чего это используется? Как это работает? Я раскрою вам эту скрытую жемчужину на нескольких реальных примерах.

Подробнее

Ментальные модели React: Работа с вводом

Обновлено:

react

Как мы работаем с вводом HTML в React? Его поведение может быть удивительным. Прочитайте этот пост, чтобы получить хорошее представление о Input. И вы также сможете выполнять некоторые упражнения кунг-фу с Пандой.

Подробнее

React Mental Models: истинное лицо JSX

Обновлено:

react

Что такое тег JSX на самом деле? Это замаскированный код JavaScript. Откроем его истинное лицо!

Подробнее

Как работает JavaScript: переменная this и контекст выполнения | by Lawrence Eagles

Это пост №32 из серии, посвященной изучению JavaScript и его строительных компонентов. В процессе определения и описания основных элементов мы также поделимся некоторыми практическими правилами, которые мы используем при создании SessionStack, приложения JavaScript, которое должно быть надежным и высокопроизводительным, чтобы помочь компаниям оптимизировать цифровой опыт своих пользователей.

this переменная или ключевое слово — очень загадочная и мощная функция языка программирования JavaScript. Его часто боятся новички в JavaScript, и он может даже создать некоторые проблемы для опытных разработчиков. Это связано с непредсказуемостью объекта, на который он ссылается в данном контексте.

Хорошее понимание этой переменной требуется для точного предсказания того, на какой объект она ссылается в любом контексте. Как только это приобретено, оно становится бесценным инструментом в руках разработчика JavaScript.

эта переменная в JavaScript ведет себя иначе, чем в других языках программирования. Хотя он относится к объекту в данном контексте, его поведение непоследовательно. Следовательно, это трудно понять.

В этой статье мы узнаем о поведении переменной this в различных контекстах выполнения в JavaScript.

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

Давайте узнаем об этих фундаментальных аспектах JavaScript в следующем разделе:

Каждый бит нашего кода в JavaScript выполняется в контексте выполнения.

Контекст выполнения является оболочкой для текущего исполняемого кода.

В двух словах, контекст выполнения — это абстрактный контекст, который содержит информацию об окружении исполняемого в данный момент кода.

Когда механизм JavaScript начинает выполнение файла JavaScript, то есть когда механизм JavaScript начинает читать наш код, он создает контекст выполнения, даже если в файле JavaScript нет кода для выполнения.

Рассмотрим изображение ниже:

Изображение выше иллюстрирует глобальный контекст выполнения. Он состоит из следующего:

  1. Глобальный объект. В браузере это объект окна.
  2. это переменная . Каждый контекст выполнения предоставляет переменную this , которая ссылается на объект, которому принадлежит исполняемый в данный момент код.
  3. Окружение переменных — место в памяти, где живут переменные.
  4. Внешняя среда. Когда мы выполняем код внутри функции, внешней средой является код вне этой функции — на глобальном уровне он равен нулю.

Кроме того, контекст выполнения создается в два этапа, а именно:

  1. Фаза создания: на этой стадии движок JavaScript проходит через наш код и добавляет все переменные и функции в память.
  2. Этап выполнения: На этом этапе значения присваиваются переменным и вызываются функции.

При каждом вызове функции создается новый контекст выполнения, который добавляется на вершину стека выполнения.

Стек выполнения — это стек со структурой LIFO (последним поступил — первым обслужен), в котором хранятся все контексты выполнения, созданные во время выполнения кода.

Стек выполнения позволяет движку JavaScript отслеживать порядок выполнения.

Давайте подробнее рассмотрим некоторые примеры кода.

Рассмотрим код ниже:

Когда приведенный выше код запускается, создается глобальный контекст выполнения, и наш код выполняется синхронно. Оператор console.log в глобальном контексте выполнения выполняется, и «hello from global» регистрируется в консоли.

Затем выполняется вызов функции a() , который создает новый контекст выполнения и добавляет его в начало стека выполнения. Код в этой функции теперь будет выполняться синхронно.

Здесь первые console.log Заявление достигнуто ведение журнала «функция a выполняется» . Затем движок JavaScript сталкивается с другим вызовом функции — вызовом b() , и это создает новый контекст выполнения и добавляет его в начало выполнения — до того, как код в функции a() будет полностью выполнен.

Следовательно, код в функции b() будет выполнен. Таким образом, «функция b выполняется» и «функция b() завершена» будет записано в консоль.

Когда механизм JavaScript завершает выполнение функции b() , контекст выполнения извлекается из стека выполнения, а затем выполняется оставшийся код в функции a() , таким образом регистрируется «функция a завершена в консоль.

Изображение ниже иллюстрирует поток выполнения приведенного выше примера кода:

Зная эти две концепции, мы теперь можем погрузиться в поведение эта переменная в разных контекстах в JavaScript.

Глобальный контекст выполнения:

Глобальный контекст выполнения является базовым контекстом выполнения. Это относится к контексту выполнения, созданному по умолчанию, когда движок JavaScript начинает читать наш код.

Когда мы говорим глобальный, мы имеем в виду что-то, что не находится внутри функции, поэтому оно доступно везде в нашем коде.

Глобальный контекст выполнения создает глобальный объект и специальную переменную, называемую это переменная .

В глобальном контексте выполнения эта переменная ссылается на глобальный объект.

Рассмотрим код ниже:

Контекст выполнения функции:

Контекст выполнения функции аналогичен глобальному контексту выполнения. Он также проходит фазу создания и выполнения и имеет свою переменную среду и эту переменную .

Внутри функции this 9Переменная 0092 ссылается на объект в зависимости от того, как вызывается функция.

Если значение this не задано вызовом, значение this относится к глобальному объекту — объекту окна в браузерах.

Однако в строгом режиме значение this равно undefined , если оно не установлено при входе в контекст выполнения.

Рассмотрим код ниже:

Контекст функционального метода:

В приведенном выше примере значение this в функции b() равно undefined , потому что функция b() была вызвана напрямую, а не как метод — свойство объекта.

Когда вызывается метод — функция объекта, привязка this устанавливается к объекту. Таким образом, если мы вызовем функцию b() выше как свойство объекта окна, мы не получим undefined .

Рассмотрим код ниже:

То же верно для любого объекта JavaScript, как показано ниже:

Обратный вызов:

Рассмотрим код ниже

В приведенном выше коде значение переменной this в наборе 8 функция обратного вызова undefined . Это выявляет несоответствие в поведении переменной this в JavaScript.

Хотя мы продемонстрировали, что при вызове метода это значение относится к объекту, содержащему этот метод. Здесь это правило не работает.

Есть три способа получить доступ к этому в функции обратного вызова выше, а именно:

  1. Явная установка этого:

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

Рассмотрим код ниже

Мы уже отмечали, что в методе этот указывает на объект, содержащий этот метод. Таким образом, в методе sayName this указывает на объект Person. Однако в обратном вызове setTimeout это равно undefined . Чтобы получить доступ к свойствам объекта Person в обратном вызове setTimeout , мы сохраняем ссылку this в методе sayName в переменную с именем self .

self затем используется в обратном вызове.

2. Использование функции стрелки

Это самый простой и рекомендуемый способ решения проблемы. Поведение this переменной в объявлениях функций ES5 может быть очень трудно предсказать. Это может привести к ошибкам, которые трудно устранить.

ES6 стрелка — лямбда-функции не имеют это 9привязка 0092. Подразумевается, что это просматривается в области видимости как обычная переменная. Таким образом, решение состоит в том, чтобы использовать функцию стрелки в качестве обратного вызова setTimeout.

Рассмотрим код ниже

3. Использование привязки

Это наиболее техническое из трех решений.

Представленный в ES 5 метод .bind() является очень мощным методом JavaScript, особенно в парадигме функционального программирования.

Прежде чем решать задачу этим методом, рассмотрим .связать() .

Давайте начнем с рассмотрения кода ниже:

Метод bind() позволяет нам явно связать с этим . При вызове функции он привязывает значение this к своему первому аргументу и возвращает новую копию этой функции.

В приведенном выше коде bind() привязывает значение this к объекту разработчика и возвращает новую функцию, хранящуюся в переменной boostedLogDevName .

Таким образом, мы можем получить доступ к методу getDevName из функции boostedLogDevName .

Точно так же мы можем решить нашу задачу обратного вызова, явно привязав этот к объекту Person, как показано ниже:

Конструктор функции

в конструктор.

Также оператор new создает новый объект и привязывает эту переменную к объекту.

Рассмотрим код ниже:

Классы

Подобно обычным функциям — поскольку класс JavaScript является специальной функцией, значение this в методе зависит от того, как он вызывается.

Однако, чтобы всегда ссылаться на экземпляр класса, общепринятым шаблоном является привязка метода класса в конструкторе.

Рассмотрим код ниже:

И

В приведенных выше примерах мы видим, что без явной привязки это , контекст метода printName меняется. Следовательно, наш код выдает ошибку.

Поведение этой переменной в JavaScript довольно загадочно. Следовательно, это аспект JavaScript, который трудно освоить. Несмотря на это, следуя рекомендациям из нашего обсуждения выше, разработчик должен иметь возможность использовать с этим практически без проблем.

Кроме того, ниже приведены некоторые рекомендации, которым необходимо следовать при использовании это в JavaScript.

Имеет разные значения в зависимости от того, где используется:

  • В методе этот относится к объекту-владельцу.
  • Один, этот относится к глобальному объекту.
  • В функции этот ссылается на глобальный объект.
  • В функции в строгом режиме этот не определен.
  • В событии этот относится к элементу, получившему событие.
  • Такие методы, как call() и apply(), могут ссылаться на этот на любой объект.

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *