자바스크립트의 함수는 호출될 때, 매개변수로 전달되는 인자값 이외에, arguments 객체와 this를 암묵적으로 전달받는다.
자바스크립트의 경우, 함수호출 방식에 의해 this에 바인딩할 객체가 동적으로 결정된다.
다시 말해, 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되는 것이 아니고, 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정된다.
함수 호출 방식
1. 함수 호출
2. 메소드 호출
3. 생성자 함수 호출
4. apply/call/bind 호출
var foo = function () {
console.dir(this);
};
//1. 함수호출
foo(); // window
// window.foo();와 동일
//2. 메소드 호출
var obj = { foo: foo };
obj.foo(); // obj
//3. 생성자 함수 호출
var instance = new foo(); //instance
//4. apply/call/bind 호출
var bar = { name : 'bar' };
foo.call(bar); //bar
foo.apply(bar); //bar
foo.bind(bar)(); //bar
함수호출 방식 중, 이번에는 '함수 호출'에 대해 알아보자!
전역객체(Global Object)는 모든 객체의 유일한 최상위 객체를 의미.
- 일반적으로 Browser-side : window객체를 의미,
- Server-side(Node.js) : global객체를 의미
// in browser console
this === window // true
// in Terminal
this === global // true
전역객체는 전역 스코프(Global Scope)를 갖는 전역 변수(Global variable)를 프로퍼티로 소유.
글로벌 영역에 선언한 함수는 전역 객체의 프로퍼티로 접근할 수 있는 전역 변수의 메소드이다.
var ga = 'Global Variable';
console.log(ga); // 'Global Variable'
console.log(window.ga); // 'Global Variable'
function foo(){ //글로벌영역에 선언한 함수
console.log('invoked!');
}
window.foo(); //전역 객체(window)의 프로퍼티로 접근할 수 있는 '전역 변수의 메소드'
//'invoked!'
//전역객체인 window객체가 이렇게 구성되어있지 않을까 :)
window {
ga: 'Global Variable',
foo: function() {
console.log('invoked!');
}
}
함수호출 시, 기본적으로 this는 전역객체(Global object)에 바인딩된다. 전역함수는 물론이고, 심지어 내부함수의 경우도 this는 외부함수가 아닌 전역객체에 바인딩된다.
function foo(){ //함수호출 시, this는 전역객체에 바인딩
console.log("foo's this: ", this); // window
function bar(){ //내부함수의 경우도, this는 전역객체에 바인딩
console.log("bar's this: ", this); // window
}
bar();
}
foo(); //함수 호출
또한, 메소드의 내부함수일 경우에도 this는 전역객체에 바인딩된다.
var value = 1;
var obj = {
value: 100,
foo: function(){ //메소드 호출의 경우, 메소드 내부의 this는 해당 메소드를 소유한 객체에 바인딩.
console.log("foo's this: ", this); //foo메소드를 소유한 객체인 obj
console.log("foo's this.value: ", this.value); //obj.value이므로 100
function bar(){ //메소드의 내부함수 호출
console.log("bar's this: ", this); // window 메소드의 내부함수의 this는 전역객체에 바인딩
console.log("bar's this.value: ", this.value); //1 === window.value
}
bar();
}
}'
obj.foo(); //메소드 호출
콜백함수의 경우에도 this는 전역객체에 바인딩된다.
var value = 1;
var obj = {
value: 100,
foo: function(){
setTimeout(function(){ //콜백함수의 this는 전역객체에 바인딩
console.log("callback's this: ", this); // window
console.log("callback's this.value: ", this.value); // 1 === window.value
}, 100);
}
};
obj.foo();
내부함수는 일반함수, 메소드, 콜백함수 어디에서 선언되었든 관계없이 this는 전역 객체를 바인딩한다.
내부함수의 this가 전역객체를 참조하는 것을 회피하는 방법은 아래와 같다.
var value = 1;
var obj = {
value: 100,
foo: function(){
var that = this; //메소드 내 this는 해당 메소드를 소유한 객체. 즉, obj
console.log("foo's this: ", this); // obj
console.log("foo's this.value: ", this.value); //100
function bar(){ //내부함수
console.log("bar's this: ", this); // window (내부함수의 this는 전역객체에 바인딩.)
console.log("bar's this.value: ", this.value); // 1
console.log("bar's that: ", that); // obj. 이 scope 밖에 있는 that을 가리킨다.
console.log("bar's that.value: ", that.value); // 100
},
bar();
},
};
obj.foo(); //메소드 호출
위 방법 이외에도 자바스크립트는 this를 명시적으로 바인딩할 수 있는 apply, call, bind 메소드를 제공한다.
var value = 1;
var obj = {
value: 100,
foo: function() { //메소드 호출
console.log("foo's this: ", this); // obj 메소드 호출 시 this는 메소드를 소유한 객체에 바인딩
console.log("foo's this.value: ", this.value); // 100
function bar(a, b) { // 내부함수
console.log("bar's this: ", this); //obj
console.log("bar's this.value: ", this.value); //100
console.log("bar's arguments: ", arguments);
}
bar.apply(obj, [1, 2]);
bar.call(obj, 1, 2);
bar.bind(obj)(1, 2);
}
};
obj.foo(); //메소드 호출
bar 내부의 this값을 obj 객체로 설정하고, bar함수의 매개변수는 배열로 a=1, b=2로 전달되었다.
참고사이트:
'JavaScript' 카테고리의 다른 글
화살표 함수의 this (0) | 2023.09.15 |
---|---|
자바스크립트 ES6모듈 내보내기/불러오기(export/import) (0) | 2023.08.16 |
이벤트 리스너(event listener) (0) | 2023.06.29 |
순수 자바스크립트를 왜 바닐라 자바스크립트(Vanilla JS)라고 할까? (0) | 2023.06.16 |
객체지향 Class 문법 (0) | 2023.05.26 |