실행 컨텍스트 내부에 있는 환경 정보 중 마지막 요소.
ThisBinding은 실행 컨텍스트가 활성화 될 때에만 동작하는 것으로 말 그대로 This가 무엇인지 연결Binding해준다.
This가 무엇을 가르키는지는 대략 다음과 같은 경우에 따라 나누어 설명해볼 수 있다.
-> 전역공간에서 this.
-> 함수 호출시 this.
-> 메서드 호출시 this.
-> callback 호출시 this.
-> 생성자 호출시 this.
전역 객체(host 객체)를 가르킨다. 전역 객체는 브라우저에서는 window / Node.js에서는 global라고 호칭한다. 자바스크립트가 실행되는 환경이나 런타임에 따라 전역 객체의 정보는 달라진다.
전역 객체(host 객체)를 가르킨다. 함수를 호출하는 주체는 전역 객체이기 때문. 그런데 전역 객체가 호출하지 않는 함수에서도 this는 전역 객체를 가르킨다.
이는 자바스크립트 자체의 버그라는 주장도 있고, 혹은 그냥 함수 호출의 특징이라는 주장도 있다. 다만 이 것이 문제라는 의견을 반영하여 Arrow Function의 개념이 탄생하였다. Arrow Function은 This를 Binding하지 않고 바로 상위 컨텍스트에 있는 this를 그대로 가져다 사용한다.
호출한 대상 객체를 가르킨다. 객체.메서드(); 라고 한다면, 메서드()의 this는 객체인 것이다. '.'을 구분점으로 삼으면 된다.
객체.프로퍼티.메서드(); 일때 메서드();의 this는? 객체.프로퍼티를 가르킨다.
var a = {
b: {
c: function() {
console.log(this);
}
}
};
a.b.c();
이 코드에서 c 함수 내부에서 this로 가르키는 대상은 a.b에 해당한다.
메서드 호출시 This의 대상 예시.
var num = 10;
var object = {
num: 20,
b: function() {
console.log(this.num);
0이 출력된다. object 객체의 프로퍼티 num.
function c() {
console.log(this.num);
10이 출력된다. 전역 객체의 프로퍼티 num.
그런데 정확하게는 전역 객체의 프로퍼티 num가 아니라 전역변수 num을 반환받았다.
전역 변수가 전역 객체의 프로퍼티로 간주된 것이다.
}
c();
}
};
object.b();
메서드 내부에서 함수 호출이 일어나면? 상위 컨텍스트의 호출 방식과 상관없이 함수 호출시 this와 동일하게 전역 객체를 가르킨다.
그렇다면 개발자가 인위적으로 this의 대상을 다르게 할 수 있을까? 있다.
var num2 = 10;
var object2 = {
num2: 20,
b: function() {
var self = this;
console.log(this.num2);
function c() {
console.log(self.num2);
}
c();
}
};
object2.b();
위 코드 상에서 b 함수의 this는 object2를 가르키고, c 함수의 this는 전역 객체를 가르킨다. 그런데 c의 this와 b의 this가 동일한 대상을 가르키도록 하고 싶다면? b의 this를 변수로 가져온 다음 c 내부에서 사용해주면 호출 주체가 다른 두 함수의 this가 같은 대상을 가르키도록 우회할 수 있다.
c 컨텍스트는 LexicalEnvironment에서 self를 찾는다, self가 없으니 Scope Chain을 통해 outerEnvironmentReference를 타고 상위 컨텍스트 b의 LexicalEnvironment에서 self를 찾는다.
b 컨텍스트의 LexicalEnvironment는 self가 있다. self의 this는 b를 호출한 object2. c 컨텍스트의 self.num2는 곧 b의 num2를 가르키게 된다.
변수를 이용해서 this가 가르키는 대상을 조절할 수 있는 것이다.
화살표 함수Arrow Function과 일반 함수의 차이점.
Arrow Function은 자신만의 This를 Binding하지 않고 바로 상위 컨텍스트에 있는 this를 그대로 가져다 사용한다.
var num3 = 10;
var object3 = {
num3: 20,
b: function() {
console.log(this.num3);
const c = () => {
console.log(this.num3);
}
c();
}
};
object3.b();
Arrow Function c는 This를 Binding하지 않고 바로 상위 컨텍스트에 있는 this를 사용하므로 b가 가르키는 것과 동일하다.
Arrow Function가 존재하지 않았던 ES5 시대까지는 call이나 apply를 사용하였으나 메서드 내부에서의 우회방법을 더 많이 사용하였다고 한다.
callback 호출시 this.
기본적으로 함수 호출시 this와 동일하다.
생성자 호출시 this.
새로 생성되는 인스턴스를 가르킨다.
this를 명시적으로 binding하는데 사용되는 방법.
function a(x, y, z) {
console.log(this, x, y, z);
}
var b = {
bb: 'bbb'
};
a.call(b, 1, 2, 3);
a.apply(b, [1, 2, 3]);
var c = a.bind(b);
c(1, 2, 3);
var d = a.bind(b, 1, 2);
d(3);
이 코드 상에 있는 4가지 동작 모두 동일한 출력값을 반환한다. ({bb: "bbb"} 1 2 3) 즉, 모두 동일한 동작을 한다는 뜻이다.
call, apply는 함수를 호출 할 때 this가 가르킬 대상을 인자로 넣어주면 함수 호출시 명시적으로 this를 binding할 수 있다.
다만 apply의 경우 this 이외에 인자들을 배열의 형태로 사용해야 한다.
bind는 함수를 실행하지는 않고, this가 가르킬 대상은 인자로 받아 binding 해준다.
정재남 - 코어 자바스크립트.