- The JavaScript this Keyword
- Note
- this in a Method
- this Alone
- Example
- Example
- this in a Function (Default)
- Example
- this in a Function (Strict)
- Example
- this in Event Handlers
- Example
- Object Method Binding
- Example
- Example
- Explicit Function Binding
- See Also:
- Example
- Function Borrowing
- Example
- This Precedence
- Явное указание this: «call», «apply»
- Метод call
- «Одалживание метода»
- Ещё пример: [].slice.call(arguments)
- Метод apply
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).
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: «call», «apply»
Материал на этой странице устарел, поэтому скрыт из оглавления сайта.
Более новая информация по этой теме находится на странице https://learn.javascript.ru/call-apply-decorators.
Итак, мы знаем, что this – это текущий объект при вызове «через точку» и новый объект при конструировании через new .
В этой главе наша цель получить окончательное и полное понимание this в JavaScript. Для этого не хватает всего одного элемента: способа явно указать this при помощи методов call и apply .
Метод call
func.call(context, arg1, arg2, . )
При этом вызывается функция func , первый аргумент call становится её this , а остальные передаются «как есть».
Вызов func.call(context, a, b. ) – то же, что обычный вызов func(a, b. ) , но с явно указанным this(=context) .
Например, у нас есть функция showFullName , которая работает с this :
Пока объекта нет, но это нормально, ведь JavaScript позволяет использовать this везде. Любая функция может в своём коде упомянуть this , каким будет это значение – выяснится в момент запуска.
Вызов showFullName.call(user) запустит функцию, установив this = user , вот так:
function showFullName() < alert( this.firstName + " " + this.lastName ); >var user = < firstName: "Василий", lastName: "Петров" >; // функция вызовется с this=user showFullName.call(user) // "Василий Петров"
После контекста в call можно передать аргументы для функции. Вот пример с более сложным вариантом showFullName , который конструирует ответ из указанных свойств объекта:
var user = < firstName: "Василий", surname: "Петров", patronym: "Иванович" >; function showFullName(firstPart, lastPart) < alert( this[firstPart] + " " + this[lastPart] ); >// f.call(контекст, аргумент1, аргумент2, . ) showFullName.call(user, 'firstName', 'surname') // "Василий Петров" showFullName.call(user, 'firstName', 'patronym') // "Василий Иванович"
«Одалживание метода»
При помощи call можно легко взять метод одного объекта, в том числе встроенного, и вызвать в контексте другого.
Это называется «одалживание метода» (на англ. method borrowing).
Используем эту технику для упрощения манипуляций с arguments .
Как мы знаем, arguments не массив, а обычный объект, поэтому таких полезных методов как push , pop , join и других у него нет. Но иногда так хочется, чтобы были…
Нет ничего проще! Давайте скопируем метод join из обычного массива:
function printArgs() < arguments.join = [].join; // одолжили метод (1) var argStr = arguments.join(':'); // (2) alert( argStr ); // сработает и выведет 1:2:3 >printArgs(1, 2, 3);
- В строке (1) объявлен пустой массив [] и скопирован его метод [].join . Обратим внимание, мы не вызываем его, а просто копируем. Функция, в том числе встроенная – обычное значение, мы можем скопировать любое свойство любого объекта, и [].join здесь не исключение.
- В строке (2) запустили join в контексте arguments , как будто он всегда там был.
Здесь метод join массива скопирован и вызван в контексте arguments . Не произойдёт ли что-то плохое от того, что arguments – не массив? Почему он, вообще, сработал?
Ответ на эти вопросы простой. В соответствии со спецификацией, внутри join реализован примерно так:
function join(separator) < if (!this.length) return ''; var str = this[0]; for (var i = 1; i < this.length; i++) < str += separator + this[i]; >return str; >
Как видно, используется this , числовые индексы и свойство length . Если эти свойства есть, то все в порядке. А больше ничего и не нужно.
В качестве this подойдёт даже обычный объект:
var obj = < // обычный объект с числовыми индексами и length 0: "А", 1: "Б", 2: "В", length: 3 >; obj.join = [].join; alert( obj.join(';') ); // "A;Б;В"
…Однако, копирование метода из одного объекта в другой не всегда приемлемо!
Представим на минуту, что вместо arguments у нас – произвольный объект. У него тоже есть числовые индексы, length и мы хотим вызвать в его контексте метод [].join . То есть, ситуация похожа на arguments , но (!) вполне возможно, что у объекта есть свой метод join .
Поэтому копировать [].join , как сделано выше, нельзя: если он перезапишет собственный join объекта, то будет страшный бардак и путаница.
Безопасно вызвать метод нам поможет call :
function printArgs() < var join = [].join; // скопируем ссылку на функцию в переменную // вызовем join с this=arguments, // этот вызов эквивалентен arguments.join(':') из примера выше var argStr = join.call(arguments, ':'); alert( argStr ); // сработает и выведет 1:2:3 >printArgs(1, 2, 3);
Мы вызвали метод без копирования. Чисто, безопасно.
Ещё пример: [].slice.call(arguments)
В JavaScript есть очень простой способ сделать из arguments настоящий массив. Для этого возьмём метод массива: slice.
По стандарту вызов arr.slice(start, end) создаёт новый массив и копирует в него элементы массива arr от start до end . А если start и end не указаны, то копирует весь массив.
Вызовем его в контексте arguments :
function printArgs() < // вызов arr.slice() скопирует все элементы из this в новый массив var args = [].slice.call(arguments); alert( args.join(', ') ); // args - полноценный массив из аргументов >printArgs('Привет', 'мой', 'мир'); // Привет, мой, мир
Как и в случае с join , такой вызов технически возможен потому, что slice для работы требует только нумерованные свойства и length . Всё это в arguments есть.
Метод apply
Если нам неизвестно, с каким количеством аргументов понадобится вызвать функцию, можно использовать более мощный метод: apply .
Вызов функции при помощи func.apply работает аналогично func.call , но принимает массив аргументов вместо списка.
func.call(context, arg1, arg2); // идентичен вызову func.apply(context, [arg1, arg2]);
В частности, эти две строчки сработают одинаково:
showFullName.call(user, 'firstName', 'surname'); showFullName.apply(user, ['firstName', 'surname']);
Преимущество apply перед call отчётливо видно, когда мы формируем массив аргументов динамически.
Например, в JavaScript есть встроенная функция Math.max(a, b, c. ) , которая возвращает максимальное значение из аргументов:
При помощи apply мы могли бы найти максимум в произвольном массиве, вот так:
var arr = []; arr.push(1); arr.push(5); arr.push(2); // получить максимум из элементов arr alert( Math.max.apply(null, arr) ); // 5
В примере выше мы передали аргументы через массив – второй параметр apply … Но вы, наверное, заметили небольшую странность? В качестве контекста this был передан null .
Строго говоря, полным эквивалентом вызову Math.max(1,2,3) был бы вызов Math.max.apply(Math, [1,2,3]) . В обоих этих вызовах контекстом будет объект Math .
Но в данном случае в качестве контекста можно передавать что угодно, поскольку в своей внутренней реализации метод Math.max не использует this . Действительно, зачем this , если нужно всего лишь выбрать максимальный из аргументов? Вот так, при помощи apply мы получили короткий и элегантный способ вычислить максимальное значение в массиве!
В современном стандарте call/apply передают this «как есть». А в старом, без use strict , при указании первого аргумента null или undefined в call/apply , функция получает this = window , например: