Рубрики
Без рубрики

Связывание «Это» в JavaScript

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

Автор оригинала: Diego Palacios Lepore.

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

И да, я сделал этот странный рисунок на вершине 😀

Во-первых, важно понимать, что Это обязательное Не определяется, когда функция объявлена, вместо этого она определена, когда вызывается функция, а также основана на том, как была вызвана эта функция.

Шаг 1: где

Первое, что нам нужно сделать, это найти, где функция была вызвана в нашей программе. Это могло быть вызвано либо из Глобальный контекст исполнения или из Контекст местного исполнения И единственный способ найти нашу функцию Call-сайт (Помимо просмотра непосредственно в нашем коде) – смотреть на Стек вызовов Отказ Вот очень простой пример, который вы можете попробовать в консоли, чтобы увидеть стек.

Сначала скопируйте и вставьте следующий код в консоли вашего браузера:

function baz() {
    bar()
}

function bar() {
    foo()
}

function foo() {
    debugger
}

baz()

Тогда в devtools , под вкладкой источников, а затем под Стек вызовов Раздел, вы увидите список функций. Таким образом, мы можем точно знать, что foo () Call-сайт это Бар () и Бар () Call-сайт это Баз () и, наконец, Баз () Call-сайт это Глобальный контекст исполнения , который в этом случае показан как анонимный Отказ

foo         (VM431:10)
bar          (VM431:6)
baz          (VM431:2)
(anonymous) (VM431:13) 
Alt Text.

Теперь, когда мы знаем, как найти нашу функцию (где) Давайте поговорим о наборе правил, которые определяют Это обязательное (Как) Отказ

Шаг 2: Как

Когда функция вызывается, новый Контекст местного исполнения создано. Контекст местного исполнения Имеет информацию о функции (ее место в стеке вызовов, длина аргументов и – среди прочего – свойство, называемое это ).

Значение это (Какой объект это указывает на), определяется на основе Как Функция вызывается.

Мы можем вызвать наши функции 4 разными способами, следуя 4 различным правилам, а именно:

  • Обязательное по умолчанию
  • Неявное обязательство
  • Явная связывание
  • Новое обязательство

Дополнительно: я также расскажу о том, как Это связывание определяется на функциях стрелки.

Обязательное по умолчанию

var x = 20

function foo() {
  console.log(this.x)
}

foo.x = 40

foo()  // 20 

А Привязка по умолчанию сделано, когда мы делаем регулярные функции, как мы здесь сделали здесь с foo () Отказ В не строгий Режим Это обязательное будет ссылаться на Глобальный объект , но на Строгий режим Это будет undefined Отказ

Стоит отметить, что в первой строке мы объявляем переменную х и назначить значение 20. И это все равно что делать window.x Отказ Короче говоря, в Глобальный объект , и это причина, почему this.x 20.

Когда Foo вызывается, что-то вроде это происходит под капотом:

foo.call(window)   // non-strict

foo.call(undefined)   // strict

Хотя мы пересмотрим эту тему позже в одном из 4 правил, я кратко объясню, что такое Звоните () Метод делает здесь: Звоните () Метод явно настройка к какому объекту это будет обязан.

Неявное обязательство

Когда мы вызываем функцию в контексте объекта, это указываю на этот объект. Давайте посмотрим на следующий код:

var x = 20 

const myObj = {
  x: 50,
  foo: function() {
     console.log(this.x)
  }
}

myObj.foo() // 50

Я хотел бы уточнить, что анонимная декларация функций в myobj.foo (АКА метод, поскольку он объявлен внутри объекта) не принадлежит Myobj Отказ Помните, что поскольку функции являются Callable объекты Они назначаются со ссылкой (например, все объекты), в отличие от примитивных значений, которые назначены копией.

Для того, чтобы проиллюстрировать мою точку зрения, рассмотрите следующий код:

var x = 20 

const myObj = {
  x: 50,
  foo: function() {
     console.log(this.x)
  }
}

myObj.foo()  // 50

const foo = myObj.foo
foo()  // 20

Когда мы объявляем const foo Мы назначаем ссылку на ту же функцию myobj.foo указывает, а затем, делая автономный вызов Foo Применяется правило связывания по умолчанию, а поскольку мы не используем Строгий режим , это указывает на Глобальный объект В этом случае окно Отказ

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

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

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

Рассмотрим следующий код:

const obj = {
  x: 'Hi there'
}

function foo(name, age) {
  console.log(
    `${this.x}, my name is ${name}, and I'm ${age} years old`
  )
}

foo.call(obj, 'Diego', 31)  
// 'Hi there, my name is Diego, and I'm 31 years old'

foo.apply(obj, ['Diego', 31])  
// 'Hi there, my name is Diego, and I'm 31 years old'

const bar = foo.bind(obj, 'Diego', 31)
bar()  // 'Hi there, my name is Diego, and I'm 31 years old'

Давайте поговорим о каждом из методов вызова в нашем фрагменте:

  • Звоните () : Вызывает и получает (в качестве своего первого параметра) объект, который явно связан с это Отказ Он также получает аргументы функции, разделенные запятой.

  • Применить () : Это то же самое, что и Звоните () , но единственное отличие состоит в том, что аргументы передаются внутри массива.

  • Bind () : Это также похоже на Звоните () Но вместо немедленно вызывая функцию, она возвращает функцию с это связано с объектом, переданным в качестве своего первого аргумента. В этом фрагменте мы храним возвращенную функцию в Const А ниже, что мы делаем вызов.

Новое обязательство

Вызов функции с Новый Ключевое слово в начале называется Конструктор звонит Отказ Давайте теперь рассмотрим следующий кодовый фрагмент:

function foo(name, age) {
   this.name = name
   this.age = age
}

const bar = new foo('Diego', 31)

console.log(
`My name is ${bar.name}, and I'm ${bar.age} years old`
) 

// My name is Diego, and I'm 31 years old

Когда мы делаем Конструктор звонит На методе Foo, это то, что происходит:

  1. Во-первых, это создает и вернет новый объект. Что-то вроде Object.Create ({}) Отказ

  2. это будет указывать на вновь созданный объект, который в этом случае это: бар Отказ

  3. И, наконец, вновь созданный объект связан с прототипом функции. Другими словами, бар Объект делегатов его [[Прототип]]/__прото__ к Foo ‘s Прототип объект.

Alt Text.

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

foo.prototype
/*
Output:

{ constructor: ƒ foo(name, age), __proto__: Object.prototype }
*/

bar.__proto__    

// or

Object.getPrototypeOf(bar)

/* 
Output:

{ constructor: ƒ foo(name, age), __proto__: Object.prototype }
*/

foo.prototype === bar.__proto__  // true
foo.prototype === Object.getPrototypeOf(bar) // true

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

  • где Функция была вызвана?
  • Как Функция была вызвана?

Функции стрелки и это

Но есть еще одна вещь, чтобы рассмотреть …

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

var name = 'Global'

function foo() {

  const bar = () => {
      console.log(this.name)
  }
  
  return bar
}

const obj = {
  name: 'Diego'
}

const fn = foo()
fn()  // 'Global'

const fn2 = foo.call(obj)
fn2()  // 'Diego'

Когда Foo Функция вызывается, функция стрелки наследует это от Foo Отказ

В const () С foo () Вызов является обычным/обычным вызовом функций, Привязка по умолчанию Правило применяется, поэтому в этом случае Foo это Указывает на окно Объект (если мы находимся на строгий режим это будет undefined ).

Но, в const.call (Обжим) , Явная привязка Правило применяется, поскольку мы явно устанавливаем OBJ, который будет связан с Foo это , что это obj объект.

И даже если мы сделаем fn2 () (Призывая нашу возвращенную функцию стрелки), которая согласно 4 правилам является Привязка по умолчанию он будет игнорировать эти правила и использовать Это обязательное вызова Фу, в этом случае obj Отказ

Окончательные слова

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