«Это» в javascript — один из самых важных и часто задаваемых вопросов в javascript.

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

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

Тип привязки «Это»

Привязка по умолчанию:

Когда мы вызываем или вызываем функцию в обычном режиме, применяется привязка правила по умолчанию. По умолчанию в случае браузера «окно» ссылается на это.

Давайте разберемся на примере

function foo(){
   console.log(this);  
    function bar(){
     console.log(this);
   } 
  bar()
}
foo()
// both of the console statement will print the window.
//because , here functions are invoked normally.
// even bar is being called inside function foo.

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

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

Второй тип привязки — «неявная» привязка. Вы помните, когда-то вы вызывали функцию с помощью (.) (точка)? как foo.bar(). Да, это называется неявной привязкой. В этом случае «это» относится к вызывающему объекту.

function foo(){
  console.log(this)
}
const obj = {foo: foo}
obj.foo() // prints obj as this

Здесь «obj» вызывает «foo». Итак, «это» теперь относится к вызывающему объекту.

function foo(){
   console.log(this); 

  function bar(){
     console.log(this);
   }  
   bar()
}
const obj = {foo: foo}
obj.foo() // what do you think? function bar will print?

В приведенном выше примере «функция foo» имеет одну внутреннюю функцию «bar». и мы вызываем bar() внутри foo, поэтому вы можете подумать, что, поскольку «obj» вызывает foo, «bar» также имеет ту же привязку, что и foo, то есть вызывающий объект.

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

поэтому здесь foo имеет «obj» как this, потому что obj вызывает . Но «bar» по-прежнему вызывается обычным образом , поэтому для bar() «this» по-прежнему является «окном».

Приоритет неявной привязки выше, чем привязки по умолчанию.

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

Когда мы вызываем любую функцию, используя «call», «apply» или «bind», это явная привязка. Потому что здесь мы явно передаем «этот» объект.

function foo(){
   console.log(this)
}
const obj = {name: 'Javascript'}
foo.call(obj) // here we are passing obj as "thisArg" so now foo has "obj" as 
//this binding

Если мы передаем «null» или «undefined» в качестве thisArg при вызове, применении или привязке. Затем он начнет вести себя как привязка по умолчанию, и «привязка этого» будет окном в случае браузера env.

Приоритет явного связывания даже выше, чем у неявного связывания. Например:

function foo(){
   console.log(this)
}
const obj = {name: 'Javascript', foo: foo}
const obj1 = {name: 'HackerNoon'}
obj.foo.call(obj1) // Here "call" has more precedence over (.) dot. 
// so now foo has obj1 as this binding

Поскольку явное связывание имеет больший приоритет, чем неявное связывание, теперь «foo» имеет obj1 как «this».

Как вы думаете, каким будет результат для приведенного ниже примера?

function foo(){
   console.log(this)
}
const obj = {name: 'Javascript', foo: foo}
const obj1 = {name: 'HackerNoon'}
obj.foo.call(null)

Пожалуйста, помните, что мы обсуждали, если «null» или «undefined» передается как «thisArg» в методе вызова или применения или привязки, он начинает вести себя как «привязка по умолчанию», поэтому в этом случае «это» будет ссылаться на окно объект.

Новая привязка:

Когда мы вызываем любую функцию с «новой» клавиатурой, под капотом происходит много всего.

  1. Создается новый пустой объект.
  2. прототип этого объекта связан с прототипом функции-конструктора
  3. выполняет функцию конструктора, связывая «вновь созданный» объект как «этот»
  4. obj возвращается, если больше ничего не возвращается

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

function Foo(bar1, bar2) {
  
  this.bar1 = bar1;
  this.bar2 = bar2;
  console.log(this)
}
const obj = new Foo('bar1', 'bar2')

здесь один объект со «свойством» bar1 и bar2 является «этой» привязкой для функции Foo.

Приоритет «новой» привязки даже выше, чем «явной» или «неявной» привязки. Например:

function Foo(bar1, bar2){
   this.bar1 = bar1;
   this.bar2 = bar2;
   console.log(this)
}
const obj = {foo: Foo}
new obj.foo('bar1', 'bar2') 
//output : {bar1: 'baar1', bar2: 'bar2'}

В этом примере мы используем ключевое слово «новое» с «(.) , то есть obj.foo(), но по-прежнему «привязка этого» — это вновь созданный объект, а не «obj».

Функция стрелки (ES6):

Стрелочная функция ведет себя немного иначе, чем обычная функция. Правила, которые мы обсуждали до сих пор, не работают для функции стрелки.

Функция Arrow не имеет собственной привязки «this», поэтому она берет «this» из ближайшего окружения, имеющего эту привязку, и если такой env. «Это» всегда относится к «окну» в браузере для функции стрелки.

function foo(){
    const es6 = () => console.log(this);
    function normal(){console.log(this)};
    es6();
    normal();
}
foo()

Здесь обе функции будут печатать «окно» как «это», потому что здесь ничего особенного не происходит.

давайте изменим способ вызова «foo».

function foo(){
    const es6 = () => console.log(this); // obj
    function normal(){console.log(this)}; // window
    es6();
    normal();
}
const obj = {foo: foo}
obj.foo()

Теперь «foo» имеет «obj» как неявную привязку «this», поэтому «es6» будет печатать «obj» как это, потому что, как мы обсуждали, функция es6 принимает «ближайшее это», но «нормальная» функция по-прежнему будет печатать «окно» потому что «Правило привязки по умолчанию» по-прежнему применяется для «нормальной» функции.

So when deciding the “this” for arrow function, just look , if outside environment has any “this” binding , if yes then that’s the this binding for es6 function, if not then “window” would be the answer in browser context

const obj = {foo: () => console.log(this)}
obj.foo()

что будет на выходе?

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

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

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