Что это за хрень - понимая это, вызывайте, применяйте и связывайте в JavaScript

внешний интерфейс GitHub JavaScript Программа перевода самородков

Одна из самых неправильно понимаемых вещей в JavaScript — этоthisключевые слова. В этой статье вы узнаете о четырех правилах, разберетесьthisК чему относится ключевое слово. Неявная привязка, явная привязка, новая привязка и привязка окна. Познакомившись с этими методами, вы также изучите некоторые другие запутанные части JavaScript, такие как.call,.apply,.bindиnewключевые слова.

видео

текст

Глубокое понимание JavaScript вthisПеред ключевыми словами необходимо сделать шаг назад и понять, почемуthisКлючевые слова важны.thisРазные контексты разрешены при повторном использовании функций. другими словами,Ключевое слово this позволяет решить, какой объект должен быть в фокусе при вызове функции или метода.Все, что обсуждалось после этого, основано на этой идее. Мы хотим иметь возможность повторно использовать функции или методы в разных контекстах или в разных объектах.

Первое, на чем мы хотим сосредоточиться, это то, как судитьthisСсылки на ключевые слова. Первый и самый важный вопрос, который вы должны задать себе, пытаясь ответить на этот вопрос: «Где вызывается эта функция?".судитьthisцитата или что-тоТолькоМетод заключается в использованииthisГде вызывается этот метод ключевого слова.

Покажите это на примере, с которым вы уже хорошо знакомы, например, у нас естьgreetметод, который принимает параметр имени и отображает окно предупреждения с приветственным сообщением.

function greet (name) {
  alert(`Hello, my name is ${name}`)
}

если я спрошу тебяgreetО чем конкретно вас предупредят и как вы отреагируете? Невозможно узнать ответ, просто дав определение функции. знатьnameчто ты должен увидетьgreetпроцесс вызова функции.

greet('Tyler')

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

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

  1. неявное связывание
  2. явная привязка
  3. новая привязка
  4. переплет окна

неявное связывание

Помните, что цель здесь — рассмотреть использованиеthisопределения функций ключевых слов и сужденияthisуказывает на. Первое и наиболее распространенное правило выполнения привязки называется隐式绑定. В 80% случаев он скажет вамthisК чему относится ключевое слово.

Предположим, у нас есть такой объект

const user = {
  name: 'Tyler',
  age: 27,
  greet() {
    alert(`Hello, my name is ${this.name}`)
  }
}

Теперь, если бы вы позвонилиuserна объектеgreetметод, вы будете использовать запись через точку.

user.greet()

Это подводит нас к основному ключевому моменту правила неявной привязки. судитьthisссылки на ключевые слова,При вызове функции сначала посмотрите на левую сторону точки.. Если у вас есть «точка» для просмотра объекта с левой стороны, этот объектthisцитаты.

В приведенном выше примереuserНа "левой стороне точки" означаетthisЦитируетсяuserобъект. Так что простокаксуществуетgreetВнутренний интерпретатор JavaScript метода помещаетthisсталuser.

greet() {
  // alert(`Hello, my name is ${this.name}`)
  alert(`Hello, my name is ${user.name}`) // Tyler
}

Давайте рассмотрим аналогичный, но немного более сложный пример. Теперь наш объект должен иметь не толькоname,ageиgreetатрибут, но и добавитьmotherсвойство, и это свойство также имеетnameиgreetАтрибуты.

const user = {
  name: 'Tyler',
  age: 27,
  greet() {
    alert(`Hello, my name is ${this.name}`)
  },
  mother: {
    name: 'Stacey',
    greet() {
      alert(`Hello, my name is ${this.name}`)
    }
  }
}

Теперь возникает вопрос: о чем предупреждает каждый приведенный ниже вызов функции?

user.greet()
user.mother.greet()

всякий раз, когда судятthis, нам всем нужно посмотреть на вызывающий процесс и подтвердить, что такое «левая сторона точки». Первый звонок,userслева от точки означаетthisбудет цитироватьuser. Во втором звонкеmotherслева от точки означаетthisЦитироватьmother.

user.greet() // Tyler
user.mother.greet() // Stacey

Как уже упоминалось, примерно в 80% случаев объект будет находиться «слева от точки». Вот почему судитьthis«Посмотри налево от точки», когда тыкаешь пальцем — это первое, что ты делаешь. Но что делать, если точек нет? Это приводит нас к следующему правилу —

явная привязка

еслиgreetфункция неuserФункция объекта, просто автономная функция.

function greet () {
  alert(`Hello, my name is ${this.name}`)
}

const user = {
  name: 'Tyler',
  age: 27,
}

мы знаем, что для того, чтобы судитьthisСначала мы должны посмотреть, где вызывается эта функция. Теперь возникает вопрос, как мы можем сделатьgreetПри вызове методаthisнаправлениеuserобъект? . Мы больше не можем просто использоватьuser.greet(),так какuserнисколькоgreetметод. В JavaScript каждая функция содержит метод, который позволяет решить именно эту задачу, имя этого метода называетсяcall.

«вызов» — это метод, который есть у каждой функции, который позволяет указать контекст для функции при ее вызове.

Имея это в виду, с помощью следующего кода вы можете вызватьgreetвремя использоватьuserДелай контекст.

greet.call(user)

Снова,call— это атрибут, который есть у каждой функции, и первым переданным ему аргументом будет контекст, в котором вызывается функция. другими словами,thisбудет указывать наcallпервый параметр .

Это основа правила 2 (явная привязка), потому что мы явно (используя.call) указаноthisцитаты.

Теперь давайтеgreetСпособ внесения небольшого изменения. Что, если мы хотим передать какие-то параметры? Не только их имена, но и языки, которые они знают. как ниже

function greet (lang1, lang2, lang3) {
  alert(`Hello, my name is ${this.name} and I know ${lang1}, ${lang2}, and ${lang3}`)
}

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

function greet (lang1, lang2, lang3) {
  alert(`Hello, my name is ${this.name} and I know ${lang1}, ${lang2}, and ${lang3}`)
}

const user = {
  name: 'Tyler',
  age: 27,
}

const languages = ['JavaScript', 'Ruby', 'Python']

greet.call(user, languages[0], languages[1], languages[2])

метод работает, он показывает, как передать параметры с помощью.callфункция вызова. Однако вы можете заметить, что вам придется проходить один за другимlanguagesэлементы массива, что несколько раздражает. Было бы неплохо, если бы мы могли взять весь массив в качестве второго параметра и позволить JavaScript развернуть его для нас. Есть хорошие новости, это.applyзаниматься вещами..applyи.callПо сути то же самое, но вместо того, чтобы передавать параметры один за другим, вы можете передавать параметры массивом и.applyавтоматически расширится для вас в функции.

затем используйте.apply, наш код можно изменить на следующий, все остальное остается прежним.

const languages = ['JavaScript', 'Ruby', 'Python']

// greet.call(user, languages[0], languages[1], languages[2])
greet.apply(user, languages)

До сих пор мы узнали о.callи.applyПравило «Явная привязка», метод, вызываемый с этим правилом, позволяет указатьthisУказатель внутри метода. Последняя часть об этом правиле.bind..bindи.callТочно так же, за исключением того, что вместо немедленного вызова функции возвращается новая функция, которую можно вызвать позже. Итак, если мы посмотрим на код, который мы написали ранее, заменим.bind, это выглядит так

function greet (lang1, lang2, lang3) {
  alert(`Hello, my name is ${this.name} and I know ${lang1}, ${lang2}, and ${lang3}`)
}

const user = {
  name: 'Tyler',
  age: 27,
}

const languages = ['JavaScript', 'Ruby', 'Python']

const newFn = greet.bind(user, languages[0], languages[1], languages[2])
newFn() // alerts "Hello, my name is Tyler and I know JavaScript, Ruby, and Python"

новая привязка

Статья 3 РешениеthisЦитируемое правилоnewсвязывать. Если вы не знакомы с JavaScriptnewключевые слова, на самом деле, всякий раз, когда вы используетеnewПри вызове функции интерпретатор JavaScript создает новый объект под капотом и обрабатывает этот объект какthis. Если вы используетеnewвызвать функцию,thisбудет естественным образом ссылаться на новые объекты, созданные интерпретатором.

function User (name, age) {
  /*
    JavaScript 会在底层创建一个新对象 `this`,它会代理不在 User 原型链上的属性。
    如果一个函数用 new 关键字调用,this 就会指向解释器创建的新对象。
  */

  this.name = name
  this.age = age
}

const me = new User('Tyler', 27)

переплет окна

Если у нас есть следующий код

function sayAge () {
  console.log(`My age is ${this.age}`)
}

const user = {
  name: 'Tyler',
  age: 27
}

Как уже упоминалось, если вы хотите использоватьuserделать контекстные вызовыsayAge,ты можешь использовать.call,.applyили.bind. Но если мы не используем эти методы, а вызываем напрямую, как обычноsayAgeЧто случится?

sayAge() // My age is undefined

Не удивительно, что вы получитеMy name is undefined,так какthis.ageне определено. Вещи начали становиться волшебными. На самом деле это потому, что слева от точки ничего нет, и нам это не нужно..call,.apply,.bindилиnewключевое слово, JavaScript по умолчанию будет использоватьthisнаправлениеwindowобъект. Это означает, что если мыwindowобъект добавленageсвойство и позвоните сноваsayAgeметод,this.ageбольше не будет неопределенным и станет объектом окнаageстоимость имущества. Не верю? Давайте запустим этот код

window.age = 27

function sayAge () {
  console.log(`My age is ${this.age}`)
}

Довольно удивительно, не так ли? Поэтому правило 4window 绑定причина. Если ни одно из других правил не выполняется, JavaScript по умолчанию используетthisнаправлениеwindowобъект.


Добавлено в ES5严格模式, JavaScript по умолчанию неthisуказывает на объект окна, но правильно поставитthisостается неопределенным.

'use strict'

window.age = 27

function sayAge () {
  console.log(`My age is ${this.age}`)
}

sayAge() // TypeError: Cannot read property 'age' of undefined

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

  1. Посмотрите, где вызывается функция.
  2. Есть ли объект слева от точки? Если есть, то это ссылка на «это». Если нет, перейдите к шагу 3.
  3. Была ли функция вызвана с помощью «вызова», «применения» или «привязки»? Если это так, это явно относится к «этому». Если нет, перейдите к шагу 4.
  4. Была ли функция вызвана с «новым»? Если это так, то «это» относится к объекту, вновь созданному интерпретатором JavaScript. Если нет, перейдите к шагу 5.
  5. Вы находитесь в «строгом режиме»? Если это так, «это» не определено, если нет, перейдите к шагу 6.
  6. JavaScript странен, потому что «это» указывает на объект «окно».

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

Если вы обнаружите ошибки в переводе или в других областях, требующих доработки, добро пожаловать наПрограмма перевода самородковВы также можете получить соответствующие бонусные баллы за доработку перевода и PR. начало статьиПостоянная ссылка на эту статьюЭто ссылка MarkDown этой статьи на GitHub.


Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,продукт,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.