javascript - this
자바스크립에서 this는 함수의 현재 실행 문맥이다.
strict-mode 에서의 this
function nonStrict() {
return this
}
function strict() {
'use strict'
return this
}
console.log(nonStrict()) // window
console.log(strict()) // undefined
console.log(window.strict()) // window
함수 실행에서의 실행 문맥은 전역 객체이다. 엄격모드에의 this는 undefined이다. 하지만 일반객체냐 전역객체에 따라 this 의 결과가 달라지지만 window를 함수 호출 앞에 붙여주면 해결됩니다.
생성자 함수/ 객체에서의 this
function Fruit(color, flavor) {
this.color = color
this.flavor = flavor
this.fuc = function () {
return this
}
}
const strawberry = new Fruit('red', 'sweet')
console.log(strawberry.color) // red
console.log(strawberry.fuc()) // strawberry
new 키워드로 객체를 생성했을 경우 생성자 함수 내의 this는 new를 통해 만들어진 새로운 변수가 됩니다.
const banana = Fruit('yellow', 'sweet')
console.log(banana.color) // error
console.log(banana.fuc()) // error
new 키워드가 없으면 일반적인 함수와 동일하게 동작하므로, Fruit 함수내의 this는 window 객체가 됩니다. 하지만 banana가 함수 실행의 결과값이 할당되므로 각 property 를 가져올 수 없습니다.
일반객체
const fruit = {
name: 'apple',
color: red,
getName: function() {
return this.name
},
}
console.log(fruit.getName()) // apple
const otherFruit = fruit
otherFruit.name = 'cherry'
console.log(fruit.getName()) // cherry
console.log(otherFruit.getName()) // cherry
otherFruit.name을 cherry 설정한 뒤 fruit.getName() 호출하면 그 결과는 cherry. 그 이유는 otherFruit 은 fruit 의 레퍼런스 변수이므로 하나(otherFruit)를 변경하면 다른 하나(fruit)도 변경됩니다. 이를 피하기 위해서는 Object.assign()메서드(ES6 지원)를 이용하여 완전히 별도의 객체로 만들어야 합니다.
const newFruit = Object.assign({}, fruit)
newFruit.name = 'cherry'
console.log(fruit.getName()) // apple
console.log(newFruit.getName()) // cherry
bind, arrow function
생성자 함수 안에 또 다른 함수가 있는 경우
function Family(firstName) {
this.firstName = firstName
const names = ['yuna', 'jeongwon']
names.map(function(value, index) {
console.log(value + ' ' + this.firstName)
})
}
const Shin = new Family('Shin')
// yuna undefined
// window
// jeongwon undefined
// window
map 메서드의 서브루틴은 호출될때 map 의 context(this)로 바인드 되지 않습니다. 바인드 되지 않았다는 것은 실행문맥이 전역이라는 것이고 실행문맥이 전역이란 말은 (비엄격모드에서) 서브루틴 내 this가 window라는 것 입니다.
실행 문맥을 Family로 지정하려면 간단하게 별도의 상수를 지정해주면 됩니다.
function Family(firstName) {
this.firstName = firstName
const names = ['yuna', 'jeongwon']
const that = this
names.map(function(value, index) {
console.log(value + ' ' + that.firstName)
})
}
const Shin = new Family('Shin')
// yuna Shin
// jeongwon Shin
상수를 만들어주기 귀찮으면 bind 라는 메서드를 사용합니다.
function Family(firstName) {
this.firstName = firstName
const names = ['yuna', 'jeongwon']
names.map(
function(value, index) {
console.log(value + ' ' + this.firstName)
}.bind(this)
)
}
const Shin = new Family('Shin')
bind도 귀찮으면 이제 arrow function을 사용해줍니다.
function Family(firstName) {
this.firstName = firstName
const names = ['yuna', 'jeongwon']
names.map((value, index) => {
console.log(value + ' ' + this.firstName)
})
}
const Shin = new Family('Shin')
일반 함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되는 것이 아니고, 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정된다.
하지만 화살표 함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정된다. 동적으로 결정되는 일반 함수와는 달리 화살표 함수의 this 언제나 상위 스코프의 this를 가리킨다.