JavaScript - this 이해하기
JavaScript 에서 제일 헷갈리는 부분은 바로 이 this
가 아닐까?
JavaScript를 첫 언어로 접하신 분에게는 당최 정리가 안되는 이상한 개념이고, 이미 OOP의 개념이 익숙하신 분에게는 도대체 뭐가 뭔지 모르겠는 기괴한 개념인 것 같다.
JavaScript에서 this
를 이해하기 위해서는 Call Stack과 Call Site를 이해해야 한다.
Call Stack ¶
마치 C나 C++에서의 공부하였던 Call Stack과도 개념이 완전히 동일한 이 녀석은, JavaScript에서도 그대로 적용된다.
Call Stack은 함수가 호출되는 스택을 의미한다. 스택이라 함은, 뭔가 쌓여있다는 의미이다.
위의 그림은 인터넷에서 가져온 그림인데, C#에서의 Call Stack을 잘 나타내고 있다. Main 함수를 기준으로, Method1이 호출되고, Method1 함수 내에서 Method2 함수가 호출되고, … 반복하여, 그렇게 Method5가 호출된다.
Method5 함수의 실행이 종료되어 값을 반환(return) 하여 Method4로 돌아갈 때 돌아가기 위한 주소를 저장해놓은 Call Stack을 확인하고, Method4로 돌아가서 마저 실행하고, 실행이 종료되면 값을 반환하여 Call Stack을 참조하여 Method3으로 돌아가고, … 반복하여, Main 함수로 돌아온다.
JavaScript에서도 정확히 동일한 개념으로 동작한다. 타 언어와 차이점이 있다면, 이 Main 함수라는 것이 조금 모양이 다를 뿐이다.
브라우저에서의 JavaScript ¶
브라우저에서는 window
라는 global object가 존재한다.
JavaScript 는 모든 것을 object로 다룬다는 것을 명심해야 한다. 여기에서 object는 OOP 에서의 object가 아니라 JavaScript Object 타입, key-value 쌍을 갖는 JavaScript의 데이터 타입이다.
window
object 에서 함수도 정의되고 변수도 정의되고, 실행된다. 브라우저 내에서 동작하는 JavaScript의 경우, 결국 모든 것들은 window
객체 아래에 존재하는 것이다. 즉 Main 함수의 역할을 하는 것을 window
객체라고 볼 수 있는 것이다.
Node에서의 JavaScript ¶
Node.js의 런타임에서는 마찬가지로 global
이라는 global object가 존재한다.
브라우저와 마찬가지로, Node에서는 global
객체가 Main 함수의 역할을 한다고 볼 수 있다.
위에서 눈치를 채셨겠지만, JavaScript는 자꾸 object를 다룬다. 만약 함수가 호출이 되면, 호출된 함수가 포함된 객체가 있을 것이다. 대개는 그 객체가 global object 이므로, 이 경우 this
는 그 global object가 된다. 브라우저의 경우 window
, Node의 경우 global
이 되는 것이다.
Call Site ¶
Call Site는 함수가 호출된 지점을 의미한다. 바로 윗 문단에서 언급하였듯, JavaScript에서는 함수가 호출되는 지점에서의 포함된 객체를 찾아 해당 객체와 this
를 바인딩한다.
예시1.
var obj1 = {
item: 'item from obj1',
mtd: function() {
console.log(this.item);
}
}
var obj2 = {
item: 'item from obj2',
mtd: obj1.mtd
}
obj2.mtd(); // 'item from obj2' 를 출력한다.
예시2.
var item = 'global item!';
var obj = {
item: 'item from obj',
mtd: function() {
console.log(this.item);
}
}
var mtd = obj.mtd;
mtd(); // 'global item!' 을 출력한다.
예시3.
function func1() {
console.log(this.item);
}
function func2(fn) {
fn();
}
var obj = {
item: 'item from obj',
mtd: func1
};
var item = 'global item!';
func2(obj.mtd); // 'global item!'을 출력한다.
bind
메서드 ¶
bind
메서드는 this
를 강제로 bind
메서드를 호출한 함수로 바인딩시킨 후 새로운 함수를 반환하는 메서드이다.
bind
메서드의 원형은 Function.prototype.bind
이므로, 모든 함수는 이를 호출할 수 있다.
예시.
function speakNation() {
console.log(this.nation);
}
var person = {
name: 'Hong Kil Dong',
nation: '한국'
}
var hongSpeakNation = speakNation.bind(person);
hongSpeakNation();
apply
메서드 ¶
apply
메서드는 bind
와 유사한 일을 하는데, 차이점이 있다면 새로운 함수를 반환하는 것이 아니라 바로 해당 함수를 호출한다.
apply
메서드의 원형은 Function.prototype.apply
이므로, 모든 함수는 이를 호출할 수 있다.
예시.
function speakNation() {
console.log(this.nation);
}
var person = {
name: 'Hong Kil Dong',
nation: '한국'
}
speakNation.apply(person);
call
메서드 ¶
call
메서드는 apply
와 딱 한가지 차이점을 빼 놓고 완전히 동일하다. call
메서드는 여러 개의 파라미터를 받는 반면, apply
는 하나의 파라미터 리스트 를 받는다.
call
메서드의 원형은 Function.prototype.call
이므로, 모든 함수는 이를 호출할 수 있다.