Автор оригинала: 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)
Теперь, когда мы знаем, как найти нашу функцию (где) Давайте поговорим о наборе правил, которые определяют Это обязательное
(Как) Отказ
Шаг 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, это то, что происходит:
Во-первых, это создает и вернет новый объект. Что-то вроде
Object.Create ({})
Отказэто
будет указывать на вновь созданный объект, который в этом случае это:бар
ОтказИ, наконец, вновь созданный объект связан с прототипом функции. Другими словами,
бар
Объект делегатов его[[Прототип]]/__прото__
кFoo
‘sПрототип
объект.
Так же, как преодоление, все функции имеют Прототип
объект. У него есть только одна недвижимость, Конструктор
, что бывает ссылкой на саму функцию.
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, специально из Это и объектные прототипы
книга от Кайл Симпсон Отказ Я полностью рекомендую все книги из серии.