The this keyword in javascript

The JavaScript this Keyword

In JavaScript, the this keyword refers to an object.

Which object depends on how this is being invoked (used or called).

The this keyword refers to different objects depending on how it is used:

In an object method, this refers to the object.
Alone, this refers to the global object.
In a function, this refers to the global object.
In a function, in strict mode, this is undefined .
In an event, this refers to the element that received the event.
Methods like call() , apply() , and bind() can refer this to any object.

Note

this in a Method

When used in an object method, this refers to the object.

In the example on top of this page, this refers to the person object.

Because the fullName method is a method of the person object.

this Alone

When used alone, this refers to the global object.

Because this is running in the global scope.

In a browser window the global object is [object Window] :

Example

In strict mode, when used alone, this also refers to the global object:

Example

this in a Function (Default)

In a function, the global object is the default binding for this .

In a browser window the global object is [object Window] :

Example

this in a Function (Strict)

JavaScript strict mode does not allow default binding.

So, when used in a function, in strict mode, this is undefined .

Example

this in Event Handlers

In HTML event handlers, this refers to the HTML element that received the event:

Example

Object Method Binding

In these examples, this is the person object:

Example

const person = firstName : «John»,
lastName : «Doe»,
id : 5566,
myFunction : function() return this;
>
>;

Example

const person = firstName: «John»,
lastName : «Doe»,
id : 5566,
fullName : function() return this.firstName + » » + this.lastName;
>
>;

i.e. this.firstName is the firstName property of this (the person object).

Explicit Function Binding

The call() and apply() methods are predefined JavaScript methods.

They can both be used to call an object method with another object as argument.

See Also:

The example below calls person1.fullName with person2 as an argument, this refers to person2, even if fullName is a method of person1:

Example

const person1 = <
fullName: function() <
return this.firstName + » » + this.lastName;
>
>

const person2 = firstName:»John»,
lastName: «Doe»,
>

// Return «John Doe»:
person1.fullName.call(person2);

Function Borrowing

With the bind() method, an object can borrow a method from another object.

This example creates 2 objects (person and member).

Читайте также:  Parsing xml messages in java

The member object borrows the fullname method from the person object:

Example

const person = <
firstName:»John»,
lastName: «Doe»,
fullName: function () <
return this.firstName + » » + this.lastName;
>
>

const member = firstName:»Hege»,
lastName: «Nilsen»,
>

let fullName = person.fullName.bind(member);

This Precedence

To determine which object this refers to; use the following precedence of order.

Precedence Object
1 bind()
2 apply() and call()
3 Object method
4 Global scope

Is this in a function being called using bind()?

Is this in a function being called using apply()?

Is this in a function being called using call()?

Is this in an object function (method)?

Is this in a function in the global scope.

Источник

Ключевое слово this в JavaScript. Полное* руководство

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

image

Введение

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

Заблуждения о this

Существует несколько распространённых заблуждений относительно этого ключевого слова. Я хочу их быстренько развеять перед тем, как перейти к сути.

this — это лексический контекст.

Такое впечатление часто возникает у новичков. Им кажется, что this — это объект, в котором, как свойства, хранятся все переменные в данной области видимости. Это заблуждение происходит из того, что в одном конкретном случае это, грубо говоря, так. Если мы находимся на самом верхнем уровне, то this равняется window (в случае обычного скрипта в браузере). А как мы знаем, все переменные, объявленные на верхнем уровне, доступны как свойства window .

В общем случае это неправда. Это легко проверить.

function test() < const a = "Кто прочитал этот текст в консоли, тот скоро умрёт"; console.log(this.a); >test(); // не волнуйтесь, никто не умрёт 

this — это объект, которому принадлежит метод

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

const f = function() < console.log(this); >const object1 = < method: f >; const object2 = < method: f >; 

Так какой же из этих объектов будет её this’ом?

Важно! Даже если объект создан с помощью классов ES6, это совершенно не гарантирует, что у его метода всегда будет нужный this . Пусть вас не вводит в заблуждение сходство с классами из «нормальных» языков.

this — это джедайская техника, которую, изучив, нужно использовать везде

Читайте также:  Python run exe command

По возможности лучше избегать употребления this . Единственный случай, когда оно полностью обосновано — это ООП. В прочих местах употребление this — это не то чтобы зло, но, как правило, излишество, запутывающее код. По сути this — это дополнительный, «минус первый» аргумент функции, который передаётся туда сложным, неочевидным новичку путём. С высокой вероятностью его можно заместить обычным аргументом, и станет только лучше.

Как определить значение this

Здесь я постараюсь дать строгий и лаконичный алгоритм, с помощью которого даже неискушённый кодер сумеет понять, чему равняется this в его конкретном случае. Более многословные пояснения буду спрятаны под спойлеры, дабы не захламлять визуальное пространство.

    Мы находимся внутри функции?

В коде верхнего уровня (не находящемся внутри никакой функции) this всегда ссылается на глобальный объект. В случае обычного скрипта в браузере это — объект window . Но вообще случаи бывают разные.

  • Да: значение this такое же, как и в функции на уровень выше (т.е. содержащей данную). Вернитесь на предыдущий шаг и повторите алгоритм для неё. Если же функция не содержится ни в какой другой, this — глобальный объект.
  • Нет: смотрим следующий пункт.

Одна из основных особенностей стрелочных функций — это так называемый «лексический this ». Это значит, что значение this в стрелочной функции определяется исключительно тем, где (в каком лексическом контексте) она была создана, и никак не зависит от того, как впоследствии она была вызвана. Иногда это не то, что нам нужно, но чаще всего это делает стрелочные функции очень удобными и предсказуемыми.

  • Да: this ссылается на новый объект, находящийся «в процессе конструкции».
  • Нет: смотрим следующий пункт.

Пожалуй, стоит отдельно оговорить случай, когда речь идёт о конструкторе унаследованного ES6-класса. Тогда до вызова super() значения у this нет (обращение к нему вызовет ошибку), а после вызова super() он равняется новому объекту родительского класса.

  • Да: значение this равняется значению первого аргумента, который мы передали в метод bind при создании данной функции.
  • Нет: смотрим следующий пункт.

Метод bind создаёт копию функции, зафиксировав для неё this и, опционально, несколько первых аргументов. На самом деле при этом создаётся не просто копия функции, а, цитирую, «экзотический объект BoundFunction». Экзотичность его проявляется, в частности, в том, что повторным вызовом bind мы уже не сможем изменить this . Поэтому, строго говоря, ответ в этом пункте надо было сформулировать так: если да, то this равняется первому аргументу первого вызова bind , который привёл к созданию данной функции.

  • Да: одному Господу известно, чему будет равен this при её вызове. Идите читать документацию по той штуке, которая её станет вызывать.
  • Нет: смотрим следующий пункт.

У не стрелочной и не связанной (bound) функции значение this зависит от обстоятельств, в которых она была вызвана. Если вы не вызываете её лично, а передаёте куда-то, то в качестве this может быть или не быть подставлено неизвестное вам значение.

`use strict` document.addEventListener('keydown', function()< console.log(this); >); // в этом случае this === document. при срабатывании обработчиков DOM-событий this равняется currentTarget [1, 2, 3].forEach(function()< console.log(this); >); // а в этом случае никакого специального значения не будет, будет undefined. почему? об этом в самом конце. 
  • Да: в таком случае this равняется первому аргументу, переданному соответствующему методу.
  • Нет: смотрим следующий пункт.
Читайте также:  Adding script file to html

Ещё один способ явно задать this . Точнее, два. Однако в плане this разницы между apply и call нет никакой, разница только в том, как передаются остальные аргументы.

Собственно, из этого механизма (а также — из опыта работы с другими языками) растут ноги у убеждения, что » this — это объект, чей метод мы вызвали». Пожалуй, я просто напишу код.

'use strict'; const object1 = < method: function()< console.log(this); >> const object2 = < method: object1.method >object1.method(); // в консоли будет object1 - мы получили функцию как свойство этого объекта и немедленно вызвали object1['method'](); // аналогичный результат. этот механизм не специфичен для точечной нотации object2.method(); // в консоли будет object2 - метод "не помнит", в каком объекте он был создан, ему важно только у какого объекта он вызван 

Если мы дошли до этого пункта, значит, this не задан ни одним из механизмов, которые позволяют его задать. Существуют различные заблуждения относительно того, как ещё может передаваться this . Например, на собеседованиях мне часто говорят вот такую вещь:

const obj = < test: function()< (function()< console.log(this); >)(); //немедленно вызываемая функция внутри другой функции > > obj.test(); // мне говорят, что в консоль выведется obj. это неправда 

Или, как я уже говорил в секции «заблуждения», многие считают, что если функция является методом объекта, созданного с помощью классов ES6, то уж в ней-то this всегда будет равен этому объекту. Это тоже неправда.

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

Исторически в качестве «дефолтного» this в такие функции передавался глобальный объект. Позже этот подход был признан небезопасным. В ES5 появился строгий режим, исправляющий многие проблемы более ранних версий ECMAScript. Он включается директивой ‘use strict’ в начале файла или функции. В таком режиме «дефолтное» значение this — это undefined .

В ES6 модулях строгий режим включен по умолчанию.

Также существуют другие механизмы включения строгого режима, например, в NodeJS строгий режим для всех файлов можно включить флагом —use-strict .

P.S. Пользователь Aingis подсказал, что в случае использования конструкции with объект, переданный в неё в качестве контекста, подменяет собой глобальный объект. Пожалуй, я не стану вносить это в свой классификатор, потому что шанс встретить with в 2019+ году довольно мал. Но в любом случае это интересный момент.

P.P.S. Пользователь rqrqrqrq подсказал, что у new выше приоритет, чем у bind . Соответствующая правка в классификатор уже внесена. Спасибо!

Источник

Оцените статью