앞선 포스팅에서는 활성화 된 실행 컨텍스트에 담긴 정보들을 알아봤다. 이번 포스팅에서는 활성화 된 실행 컨텍스트에 담기는 정보 중 하나인
this 바인딩에 대해 알아보겠다. 자바스크립트에서의 this는 클래스 스코프와 관계없이 어디서든 사용할 수 있어 혼란을 야기하는 경우가 많다. 이를 고려하여 해당 포스팅에는 this가 바인딩하는 객체를 명시하는데 초점을 두겠다 🧘🏻♀️
따라서 함수를 호출한 객체에 따라 this가 가리키는 객체가 달라진다.
a() 는 전역스코프에서 호출됐다. 즉, this는 전역객체를 가리킨다.
function a() {
console.log(this); //window
}
a();
브라우저 환경에서는 window, node환경에서는 global을 가리킨다.
전역객체가 window 혹은 global 인것은 다음 코드로 입증 가능하다.
// Browser 환경
var a=1;
console.log(a); //1
console.log(window.a); //1
console.log(this.a); //1
// Nodw 환경
var a=1;
console.log(a); //1
console.log(global.a); //1
console.log(this.a); //1
전역변수와 전역객체 모두 동일한 값이 출력되는 것을 확인할 수 있다.
다만, 삭제 시에는 전역변수와 전역객체가 구분되는 것을 유의해라.
var a=1;
delete window.a; //false
console.log(a, window.a, this.a) //1 1 1
window.b=2;
delete b; //true
console.log(b, window.b, this.b) // b is not defined
이는 전역변수를 선언하면 엔진이 자동으로 전역객체의 프로퍼티로 할당하면서 configurable(변경 및 삭제 가능성)을 false로 정의하는 것이다.
함수문맥에서 this는 무엇을 가리킬까? 를 살펴보기전에 함수와 메서드의 차이를 분명히 짚고 가자.
함수와 메서드는 미리 정의한 특정한 동작을 수행하는 코드 뭉치라는 점은 동일하다.
주목할 점은 a()와 method 모두 첫번째 줄에서 정의된 함수를 참조하였음에도 다른 결과를 출력하고 있다는 것이다. 이에 대한 답은 함수와 메서드 정의에서 힌트를 얻을 수 있다.
함수는 단독으로 쓰여 전역객체에 의해 호출되므로 함수의 this는 전역객체 window를 가리키고, 메서드는 메서드가 정의된 객체에 의해 호출되므로 this는 메서드가 정의된 객체를 가리킨다.
var a = function (x) {
console.log(this, x);
};
a(1); //Window {...} 1
var obj = {
method: a,
};
obj.method(1); //{method:f} 1
this는 함수를 호출한 객체를 가리킨다는 것은 메서드 구조가 복잡해져도 일관되게 적용된다.
var a = function (x) {
console.log(this, x);
};
var obj = {
innerobj: {
method: a,
},
};
obj.innerobj.method(1); //{ method: [Function: a] } 1
method를 호출한 객체는 innerobj이기 때문에 innerobj가 출력되는 것을 확인할 수 있다.
아직까지 이해가 안된다면 이렇게 암기하자 😅
this.메서드 this.함수 이다. 메서드 혹은 함수의 바로 앞에 점에 명시되어 있는 객체가 곧 this다.
var a = function (x) {
console.log(this, x);
};
a(1);
var obj = {
method: a,
innerobj: {
innerMethod: a,
},
};
obj.method(1);
obj.innerobj.innerMethod(1);
a(1) : window.a(1) 이므로 this 는 windowobj.method(1) : this 는 objobj.innerobj.innerMethod(1) : this 는 innerobj점을 이용하여 this를 구분할 수 있게 됐지만 이는 This의 본래 의도와는 이질감이 있다. This는 활성화된 실행 컨텍스트에 담긴 정보의 일환이다. 호출 당시 스코프체인의 일관성을 유지하여 스코프에 따른 바인딩과 상속을 유지하는 것이 바람직하다. 이는 함수 포스팅에서 다룬 함수 호이스팅으로 해결할 수 있다.
var obj = {
method: function () {
console.log(this); //{ method: f}
var innerFunc = () => {
console.log(this); //{ method: f}
};
innerFunc();
},
};
obj.method();
화살표 함수를 이용하면 상위 스코프의 this를 그대로 활용할 수 있다.
만약 함수 선언문을 사용했다면? 🧐
var obj = {
method: function () {
console.log(this); //{ method: f}
var innerFunc = function () {
console.log(this); //Window {...}
};
innerFunc();
},
};
obj.method();
참고