Javascript에서 매번 헷갈리는 execution context와 this를 정리해본다.
this는 함수가 호출되는 시점에서, 함수의 소유자를 가르킨다.
즉, "this는 실행컨텍스트를 가르킨다".
Context란, 사전적인 의미로는 "문맥, 맥락"이라는 뜻을 가지고 있다.
Execution Context(실행컨텍스트)
란 함수가 실행(호출)될때의 맥락을 의미한다고 할 수 있다.
이는 호출하는 함수를 소유하고있는 소유자로도 볼 수있다.
따라서 같은함수라 하더라도 호출되는 시점에서의 소유자가 누구냐에따라 this의 값이 달라지게 된다.
let obj = {
name: "objContext",
printThis: function() {
console.log(this);
}
};
let obj2 = {
name: "objContext2",
printThis: obj.printThis
};
let printThis = obj.printThis;
// 소유자가 obj, this = obj
obj.printThis(); // obj
// 소유자가 obj2, this = obj2
obj2.printThis(); // obj2
// 소유자가 전역환경, this = window
printThis(); // widnow
// 소유자가 button element, this = btnElem
let btnElem = document.createElement("button");
btnElem.addEventListener("click", printThis);
btnElem.click(); // button element
지금까지의 내용을 다시한번 정리하면
this는 실행컨텍스트를 가리키는 값이다.
실행컨텍스트는 실행되는 순간에 정해지기때문에, this의 값은 호출시점에 따라 동적으로 변경된다.
그러나 동적으로 바뀌는 this 값을 고정시킬 수 있는 방법들이 존재한다.
Function 클래스의 기본 메소드들이다.
고정시킬 this를 파라미터로 넘겨줌으로써, this 값을 고정시켜 호출할 수 있다.
var obj = {
name: "objContext",
printThis: function() {
console.log(this);
}
};
obj.printThis() // {name: 'objContext', printThis: ƒ}
obj.printThis.call(this) // Window {0: global, …}
obj.printThis.apply(this) // Window {0: global, …}
둘의 동작은 비슷하나, 파라미터를 넘기는 방식의 차이가 있다.
func.call(thisArg[, arg1[, arg2[, ...]]])
func.apply(thisArg, [argsArray])
마찬가지로 Function 클래스의 기본 메소드다.
call
, apply
처럼 고정시키고싶은 this를 파라미터로 넘긴다.
차이점은 call, apply
는 this를 고정시켜 함수를 호출해주는 반면, bind
는 this가 고정된 새로운 함수를 return 해준다.
var obj = {
name: "objContext",
printThis: function() {
console.log(this);
}
};
var objPrintThis = obj.printThis.bind(obj);
var globalPrintThis = obj.printThis.bind(this);
// 별도의 호출이 필요하다.
objPrintThis() // {name: 'objContext', printThis: ƒ}
globalPrintThis() // Window {0: global, …}
new
키워드와 함께 호출되는 함수를 생성자함수라고 한다.
일반함수와는 다르게 new 키워드가 특별한 일을 하기때문에 this가 고정되게 된다.
생성자함수가 호출되면 다음의 과정의 일어난다.
- new 키워드에의해 새로운 객체공간이 생성
- 생성된 객체공간과 this를 바인딩 <- 이 과정에서 this가 고정된다.
- 생성된 객체를 반환
function test () {
console.log(this)
}
test() // Window {0: global, window: Window, …}
new test() // {}
일반적으로 function
키워드를 이용한 함수선언문이나 함수표현식으로 정의된 함수의 this는 실행컨텍스트를 가르킨다.
그러나 es6 부터 지원하는 화살표함수를 이용하면 this의 값을 고정시킬 수 있다.
사실 고정시킨다라기보다 Arrow Function은 this값이 없다.
스코프체인을 따라서 부모스코프의 this에 접근할 뿐이다.
(스코프는 실행컨텍스트가 아닌 렉시컬컨텍스트를 따른다)
렉시컬 컨텍스트
실행시점이 아닌, 함수가 정의되는 시점의 컨텍스트
let obj = {
name: "objContext",
printThis: () => {
// this 값이 없다. 부모스코프(=부모의 렉시컬스코프)인 global을 this로 갖게된다.
console.log(this);
}
};
let obj2 = {
name: "objContext2",
printThis: obj.printThis
};
let printThis = obj.printThis;
let btnElem = document.createElement("button");
btnElem.addEventListener("click", printThis);
// 모두 window로 고정이 되었다.
btnElem.click(); // Window {window: Window …}
obj.printThis(); // Window {window: Window …}
obj2.printThis(); // Window {window: Window …}
printThis(); // Window {window: Window …}
https://poiemaweb.com/js-this
https://www.youtube.com/watch?v=PAr92molMHU&list=PLuBMRNcyzsWxcnDdAmJWyWYXuExyP9aS1&index=6