Пора признать, что ключевое слово this в javascript — самая загадочная вещь, которая держит нас в ужасе, когда мы встречаемся с JavaScript-интервью. Его поведение было легко понять до того, как появился наш новый друг «⇒» (стрелочные функции), и теперь странное поведение ключевого слова «this» внутри стрелочной функции приводит нас в полное изумление. Итак, давайте преодолеем ужас «этого» и добавим больше любви к Javascript.
Давайте начнем в обратном порядке, сначала я скажу вам ответ, а затем мы попробуем задать несколько вопросов и понять смысл следующих пунктов.
- Обычные функции (выражение функции и объявление функции) ключевое слово this здесь указывает на объект, вызывающий функцию.
- Функции со стрелками Ключевое слово this указывает на контекст, в котором определена функция.
Слишком рано, чтобы понять? Просто помните о приведенных выше утверждениях и переходите к нашим вопросам.
Начав с нескольких простых доз, каков будет результат myObj.myNormalFunction()
? Правильный ответ 20. Поздравляем!! 🥳, чтобы сделать это правильно. Согласно нашему определению, в myNormalFunction
«это» будет указывать на объект, который вызывает эту функцию, то есть myObj
, а поскольку myObj
является экземпляром MyClass
, который имеет свойство «возраст» со значением 20, this.age
печатает 20 .
Теперь пришло время поднять нашу сложность 😎, каков будет результат myObj.myArrowFunction()
? Опять 20. Но если оба выдают одинаковый результат, значит, разницы нет🤔. Хм, а согласно нашим утверждениям, «эта» внутренняя стрелочная функция будет указывать на контекст, в котором она определена, то есть на MyClass
, а поскольку myObj
является экземпляром MyClass
, она будет указывать на myObj
, имеющее свойство age со значением 20.
Выглядит легко сейчас, верно 🥳. Тада!!! время для второго вопроса
Опять тот же вопрос, что будет на выходе myObj.myNormalFunction()
. Снова ответ тот же 20, потому что по той же причине, что и для предыдущего вопроса. Но поворот возникает, когда мы пытаемся проверить вывод myObj.myArrowFunction()
, он «не определен». Да, так что, как сказано, «это» внутри myArrowFunction
будет указывать на контекст, в котором myArrowFunction
определено, и поскольку он определен в глобальном контексте, «это» будет указывать на объект window
, у которого нет свойства с именем «возраст», поэтому ответ «не определен».
Продолжая нашу игру в догадки, попробуйте угадать вывод следующего:
Таким образом, obj.myNormalFunction()
должно напечатать 20, потому что obj
вызывает функцию и поскольку она имеет свойство age
, следовательно, печатает 20.
Теперь снова настала очередь нашего дьявола😈, что должен напечатать obj.myArrowFunction()
? Что ж, ответ «не определено». ПОДОЖДИТЕ, ЧТО!!!🤯. А как насчет нашего определения? Поскольку myArrowFunction
определяется внутри obj
, не должно ли «this» указывать на контекст, в котором определено myArrowFunction
, то есть на obj.
? Что ж, теперь нам нужно понять слово «контекст».
В контексте JS, также известном как «контекст выполнения», это специальный блок, в котором выполняется код. По умолчанию JS создает глобальный контекст для хранения кода и его выполнения. Но в тех случаях, когда мы вызываем функцию (не стрелочную функцию), JS создает совершенно новый контекст для выполнения этой функции. И кроме этих двух сценариев JS никогда не создает новый контекст.
Итак, поскольку obj
— это простой объект (не имеющий собственного контекста), определенный глобально, следовательно, он присутствует в глобальном контексте. Поскольку myArrowFunction
определено внутри этого объекта, мы можем сказать, что myArrowFunction
также присутствует в глобальном контексте, а «это» указывает на глобальный контекст, который не имеет никакого свойства age
, поэтому печатается undefined.
Если в JS есть только два контекста, т. е. функция и глобальный контекст, то как насчет классов, то класс — это просто синтаксический сахар наших обычных функций. Ниже приведен пример, который показывает класс (слева) и его эквивалентный код в функции (справа).
Разве не было загадкой понять такое странное поведение на таких простых примерах? Что ж, поздравляю🎊 с тем, что вы стали настоящим разгадчиком тайн 🧩. Вот очень маленькая загадка снова, чтобы решить для себя. Проверьте приведенный ниже код и попытайтесь объяснить, что должно быть на выходе этого кода в разделе комментариев.