this
- это ключевое слово, которое ссылается на тот или иной объект в зависимости от того, где оно записано или как была вызвана функция, где this
присутствует.
this
или другими словами контекст выполнения - это одна из тем понимание которой необходимо для изучения объектно-ориентированного программирования (ООП) в JavaScript.
this
Посмотрим чему равен this
с помощью метода console.log()
console.log(this) // this === window
или запросим значение свойства объекта, предварительно установив его, как this
.
let student = {
name: this
}
console.log(student.name) // this === window
В глобальном контексте, за пределами функций this
равен объекту window
в независимости от того, какой режим разработки установлен строгий 'use strict'
или нестрогий.
Кстати, уже здесь мы можем обратиться не только к объекту window
в целом, но также и к его свойствам.
console.log(this.onclick) // null
Если this
записывать в отдельной функции, то его значение не всегда равно window
. В нестрогом режиме всё без сюрпризов.
function testThis() {
console.log(this)
}
testThis() // в браузере window
testThis() // в Node global
В строгом режиме.
'use strict'
function testThis() {
console.log(this)
}
testThis() // undefined
Ключевое слово this
всегда динамично и указывает на тот объект в контексте которого было вызвано. В примерах выше контекст глобальный оттуда мы и видим window
. Кстати, если this
записать в функцию, которая лежит внутри другой функции, результат будет таким же.
function testThis() {
(function () {
console.log(this === window)
})()
}
testThis() // true
Теперь рассмотрим другой контекст отличный от глобального.
let student = {
name: 'Дмитрий',
course: 'HTML + CSS',
level: 'junior',
objMethod() {
console.log(this)
}
}
student.objMethod()
Вызывая функцию objMethod
, как метод объекта student
мы видим, что ключевое слово this
принимает значение этого объекта, то есть значение того объекта по отношению к которому был вызван этот метод.
let student = {
name: 'Дмитрий',
course: 'HTML + CSS',
level: 'junior',
statement() {
console.log(`${this.name} c уровнем ${this.level} хочет поступить на курс ${this.course}`)
}
}
student.statement()
Таким образом, мы можем обращаться через this
к значениям свойств объекта через их имена. В принципе запись ниже аналогична варианту с this
.
let student = {
name: 'Дмитрий',
course: 'HTML + CSS',
level: 'junior',
statement() {
console.log(`${student.name} c уровнем ${student.level} хочет поступить на курс ${student.course}`)
}
}
student.statement()
Вместо this
мы прописываем имя объекта, тем самым также обращаясь к его свойствам. Однако, если мы захотим эту функцию назначить нескольким объектам первый вариант отработает без ошибок в отличие от второго.
function statement() {
console.log(`${this.name} c уровнем ${this.level} хочет поступить на курс ${this.course}`)
}
let student1 = {
name: 'Дмитрий',
course: 'HTML + CSS',
level: 'junior',
statement
}
let student2 = {
name: 'Ольга',
course: 'Basic JavaScript',
level: 'junior',
statement
}
student1.statement() // Дмитрий c уровнем junior хочет поступить на курс HTML + CSS
student2.statement() // Ольга c уровнем junior хочет поступить на курс Basic JavaScript
Имея в арсенале this
нет надобности писать для каждого объекта одну и ту же функцию, в примере мы записали statement()
один раз, а далее назначили ее двум разным объектам. При вызове метода для student1
и student2
получили корректный результат.
Работая с this
стоит помнить, что ключевое слово определяется в момент вызова функции. Таким образом, если функцию положить в переменную и вызвать уже ее, результат будет отличным.
let student1 = {
name: 'Пётр',
statement() {
console.log(`Имя студента ${this.name}`)
}
}
student1.statement() // Имя студента Дмитрий
let anotherVar = student1.statement
anotherVar() // Имя студента
Стрелочная функция не имеют собственного контекста и если в таком случае прописать this
то ссылаться ключевое слово будет на объект ближайший по иерархии. Такая особенность удобна, когда мы хотим передать в функцию внешний контекст.
let student = {
name: 'Дмитрий',
objMethod() {
console.log(this) // {name: 'Дмитрий', objMethod: ƒ}
let arrowFunc = () => console.log(this)
arrowFunc() // {name: 'Дмитрий', objMethod: ƒ}
function funcWithinFunc() {
console.log(this)
}
funcWithinFunc() // window
}
}
student.objMethod() // student
В первых двух случаях this
ссылается на значение объекта student
, в свою очередь this
, записанная в функции funcWithinFunc
, будет равна window
.
Функция-конструктор позволяет создавать новые объекты по шаблону на основе других данных. При вызове функции конструктора this
принимает значение вновь созданного объекта, который наполняется вследствие выполнения тела функции.
function Student(name, course) {
this.name = name
this.course = course
this.school = 'LearnJS'
}
let student1 = new Student('Вера', 'JavaScript Basic')
console.log(student1)
call()
и apply()
позволяют явно настроить контекст выполнения функции, результатом работы методов будет выполнение этой функции. Методы идентичны между собой, единственное их различие, это формат в котором записываются аргументы, для call()
через запятую, для appy()
в массиве.
let student1 = {name: 'Степан'}
let student2 = {name: 'Юлия'}
let sayName = function(course) {
console.log(`${this.name} изучает ${course}`)
}
sayName.call(student1, 'JS') // Степан
sayName.apply(student2, ['HTML + CSS']) // Юлия
В первом случае мы определили контекст выполнения функции sayName
относительно объекта student1
, во втором относительно student2
и получили в console Степан и Юлия соответственно.
bind()
– это встроенный метод, который также даёт возможность зафиксировать контекст выполнения, чтобы заранее быть уверенным, какое значение будет у this
. В отличие от call()
и apply()
метод bind()
возвращает новую функцию, а не вызывает изначальную.
let student1 = {name: 'Степан'}
let student2 = {name: 'Юлия'}
let sayName = function() {
console.log(this.name)
}
sayName.bind(student1)() // Степан
sayName.bind(student2)() // Юлия
1. Ключевое слово this
позволяет работать с контекстом, получая доступ до объектов, а также имеет в арсенале методы, для того, чтобы менять этот контекст.
2. this
не является фиксированным и определяется во время выполнения кода. Таким образом, пока функция не вызвана this
не имеет значения.
3. Стрелочные функции не имеют собственного контекста и связываются с ближайшим по иерархии.
4. bind()
, call()
и apply()
- методы позволяющие управлять контекстом.
5. При вызове функции-конструктора this
принимает значение вновь созданного объекта.