들어가며
실행 컨텍스트에 관한 지난번 자료 에서 this는 실행 컨텍스트에 따라 달라진다
라는 내용을 간단하게 언급했었다.
그 때는 왜 달라지는지
에 대해서 언급을 했었다. 이번에는 어떻게 달라지는지
에 대한 내용이다.
혹시나 링크를 타고가지 않을 누군가를 위해 간단하게 말해보자면,
Execution context 가 만들어질 때
this
가 바인딩이 되기 때문이다.
그러니까 실행 중에 결정이 된다는 말이다.
추가적으로 this
를 찾다보면 this는 Lexical Scope 와 아무런 관계가 없다
라는 것을 종종 볼 수 있다. 나는 이 말을 Execution context 가 만들어질 때 activation object(variable object) 안에서 this
와 parameter
가 아예 별개의 property 로써 존재하기 때문이라고 생각한다.
앞에 내용을 읽고 이런 생각이 들 것이다.
음 그렇다면
this
는 동적으로 바인딩이 되겠구나.동적으로 바인딩이 된다면... 누가 호출했냐에 따라 바인딩이 달라지겠지? -> 맞아!
- 책 You Don't Know JS (2) 를 참고하였다.
호출부에 따른 this의 바인딩
각각의 바인딩 방식은 이름을 갖고 있지만, 나는 개인적으로 이름 때문에 처음에 this
의 바인딩을 접했을 때 더 혼란스러웠기 때문에 이름과 코드의 상황(?) 을 같이 정리해봤다.
기본 바인딩(Default binding)
아무것도 명시하지 않았을 경우
아무것도 명시하지 않았을 경우 this
가 전역 객체
혹은 undefined
에 바인딩되는 것을 말한다.
function foo() {
console.log(this.a);
}
var a = 2;
foo(); // 2
엄격 모드에서는 this
에 undefined
가 바인딩되고, 그렇지 않은 경우(위 코드)에는 this
에 전역 객체
가 바인딩된다.
암시적 바인딩(Implicity binding)
context가 있는 경우
obj.foo()
와 같이 context가 있는 경우, 그 context에 this
가 바인딩되는 것을 말한다.
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
}
obj.foo(); // 2
명시적 바인딩(Emplicity binding)
바인딩 할 객체를 명시하는 경우
call()
또는 apply()
를 사용하여 어떤 객체를 this
로 꼭 바인딩 시키는 것을 말한다.
function foo() {
console.log(this.a);
}
var obj = {
a: 2
};
foo.call(obj); // 2
하드 바인딩
명시적 바인딩을 이용하여, 항상 어떤 객체로 바인딩 시키는 것 을 말한다.
var obj = {
a: 2
};
function foo() {
console.log(this.a);
}
var bar = function() {
foo.call(obj);
}
bar(); // 2
bar.call(window); // 2
그래서 이러한 특성을 사용하여 인자를 넘기고 반환 값을 돌려받는 창구가 필요할 때 주로 쓰인다.
아래 코드는 어떤 객체의 this
를 고정시켜주는 bind()
라는 함수이다.
function foo(something) {
console.log(this.a, something);
return this.a + something;
}
function bind(fn, obj) {
return function() {
return fn.apply(obj, arguments);
}
}
var obj = {
a: 2
};
var bar = bind(foo, obj); // bar는 foo()의 this에 obj를 바인딩한 함수를 할당 받는다.
var b = bar(3); // 2 3
console.log(b); // 5
new 바인딩
new를 사용해서 객체를 만든 경우
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log(bar.a); // 2
var bar = new foo(2);
를 자세히 보자.
new foo(2);
를 하게 되면 새로운 object
가 생긴다. 이 때 이 새로운 object
의 this
에다가 bar
를 바인딩해준다.
이 경우, prototype chaining
이 어떻게 되는지를 간단하게 보고 가자.
이 때 이런 코드가 있을 때, 호출되는 것은 생성자 함수 가 아니라, 함수 foo()
의 constructor
를 호출하는 것이다. 그러니까 생성자 함수를 호출하는 것이 아니라, 함수 foo()의 생성자를 호출 하는 것이다.
(이를 통해 bar
는 foo()의 prototype 객체
에 접근할 수 있다)
정리
this
는 함수 호출 시 3가지 방법 으로, 그냥 호출 시 1가지 방법 으로 바인딩이 된다.
함수 호출 시 에는 아래의 방법으로 바인딩이 된다.
- 암시적 바인딩
var bar = obj.foo();
- 명시적 바인딩
var bar = foo.call(obj);
- new 바인딩
var bar = new foo();
그냥 호출 시 아래의 방법으로 바인딩이 된다.
var bar = foo();
'자바스크립트 JavaScript' 카테고리의 다른 글
Prototype, Inheritance (0) | 2023.01.21 |
---|---|
생성자와 This (0) | 2023.01.20 |
함수 (0) | 2023.01.19 |
Closure (0) | 2023.01.18 |
Scope (0) | 2023.01.18 |