В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
В этом блоге мы попробуем разобраться в этом на нескольких примерах.
Прежде чем перейти к рассмотрению примеров, необходимо иметь в виду два момента.
Ключевое слово "this" в обычной функции всегда зависит от того, "как вызывается функция".
Ключевое слово "this" в стрелочной функции всегда зависит от того, "где определена функция".
Рассмотрим несколько примеров
Пример 1 (Понимание this внутри обычной функции):
Создадим объект, как показано ниже
let user = { name:"Pradeep", displayName:function(){ console.info(this.name) } } user.displayName() // Pradeep let f = user.displayName f() // undefined
Когда вызывается user.displayName(), "this" внутри функции становится объектом пользователя, поскольку она вызывается с использованием объекта пользователя. Таким образом, this.name совпадает с user.name, поэтому на выходе получается "Pradeep".
При вызове f() "this" внутри функции становится глобальным объектом, так как вызывается напрямую. Таким образом, this.name совпадает с global.name, имя не определено глобально, поэтому на выходе получается "undefined".
Из приведенного примера можно сделать вывод, что ключевое слово "this" в обычной функции всегда зависит от того, "как вызывается функция".
Пример 2 (Понимание этой функции внутри стрелки):
Используем тот же объект user, но немного модифицируем его.
let user = { name:"Pradeep", displayName:function(){ const show=()=>{ console.info(this.name) } show() } } user.displayName() // Pradeep let f = user.displayName f() // undefined
Вместо того чтобы напрямую регистрировать this.name в функции displayName, мы создали функцию arrow и зарегистрировали this.name в ней, чтобы понять, как работает это ключевое слово в функции arrow.
Здесь стрелочная функция "show" определена внутри функции displayName. Таким образом, значение this внутри show совпадает со значением displayName. Если значение this меняется для displayName, то оно меняется и для show.
Когда вызывается user.displayName(), значение this внутри displayName является объектом пользователя, и show также использует это значение, поэтому выводит "Pradeep".
Когда вызывается f(), значение this внутри displayName является глобальным, и show также использует это значение, поэтому выводит undefined, так как имя не определено глобально.
Из приведенного примера можно сделать вывод, что ключевое слово "this" в стрелочной функции всегда зависит от того, "где определена функция".
Пример 3 (ключевое слово this внутри функции обратного вызова):
В javascript мы часто используем функции обратного вызова, будь то внутри обработчиков событий, таймеров или любых других функций более высокого порядка. Когда мы передаем функцию обратного вызова в качестве аргумента любой функции более высокого порядка, именно функция более высокого порядка отвечает за выполнение обратного вызова. Посмотрим, как ведет себя это ключевое слово внутри функции обратного вызова.
Создадим объект
let user = { name:"Pradeep", displayName:function(){ setTimeout(function(){ console.info(this.name) },1000) setTimeout(()=>{ console.info(this.name) },1000) } } user.displayName()
Функция обратного вызова внутри первого setTimeout является обычной функцией. Так, через 1000 миллисекунд setTimeout вызовет функцию обратного вызова. Поскольку она вызывается напрямую, без какого-либо объекта, то ее значением является глобальный объект. Поэтому она выводит неопределенное значение.
Во втором SetTimeout функция обратного вызова является стрелочной функцией. Поскольку они определены внутри функции displayName, то оба имеют одинаковое значение "this". Функция displayName вызывается с помощью пользователя. Значение this внутри displayName становится user, а обратный вызов функции arrow во втором SetTimeout также имеет то же значение "this", то есть объект user.Вот почему он выводит Pradeep через 1000 мс.
Пример в реальном времени (это внутри компонента класса в react):
import React from 'react'; class Test extends React.Component { constructor(props){ super(props) this.state = { name:"" } } updateName(){ this.setState({name:"Pradeep"}) } render() { return( <button onClick = {this.updateName}> Update Name</button> <button onClick = {()=>this.updateName()}> Update Name</button> {this.state.name} ); } } export default Test;
Мы создали компонент Test, который имеет состояние, метод updateName и метод render. При рендеринге компонента Test вызывается метод render, и значением "this" внутри метода render является экземпляр класса Test.
Поэтому следует обратить внимание на то, что значение this внутри render
Method = экземпляр Test.
В операторе return находятся 2 кнопки.
Обработчик события первой кнопки определен как
onClick = {this.updateName}
Который можно переписать так
const fun = this.updateName onClick = {fun}
Когда пользователь нажмет на кнопку, он вызовет функцию updateName напрямую, без какого-либо объекта. Таким образом, значение this внутри метода updateName становится неопределенным и this.setState() выдает ошибку.
В то время как во второй кнопке обработчик события определяется как
onClick = {()=>this.updateName()}
Когда пользователь нажимает на вторую кнопку, выполняется функция arrow, а затем функция arrow выполняет следующее.updateName(). Поскольку updateName является обычной функцией, значение параметра this внутри updateName зависит от способа его вызова. Вызов его осуществляется следующим образом.updateName(). Значение this внутри функции arrow равно значению this внутри метода render, которое равно экземпляру класса Test. Таким образом, это.setState() действует, если updateName вызывается со второй кнопки.
Вывод:
20.08.2023 18:21
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в 2023-2024 годах? Или это полная лажа?".
19.08.2023 18:39
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в частности, магию поплавков и гибкость flexbox.
19.08.2023 17:22
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для чтения благодаря своей простоте. Кроме того, мы всегда хотим проверить самые последние возможности в наших проектах!
18.08.2023 20:33
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий их языку и культуре.
14.08.2023 14:49
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип предназначен для представления неделимого значения.
05.08.2023 16:43
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции обеспечивают мощный способ выполнения операций на битовом уровне, предлагая более эффективные решения для определенных задач. В этом блоге мы рассмотрим, как...