다른 프로그래밍 언어에서 this가 가리키는 것과 JavaScript에서 this가 가리키는 것과는 좀 다르다. this가 가리킬 수 있는 객체는 정확히 5종류나 된다.
this;
Global Scope에서도 this가 사용될 수 있고 이때에는 Global 객체를 가리킨다.
foo();
이때에도 this는 Global 객체를 가리킨다.
ES5 Note: strict 모드에서 더는 Global 객체를 가리키지 않고 대신
undefined를 가리킨다.
test.foo();
이 경우에는 this가 test를 가리킨다.
new foo();
new 키워드로 생성자를 실행시키는 경우에 이 생성자 안에서 this는 새로 만들어진 객체를 가리킨다.
function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]); // a = 1, b = 2, c = 3으로 넘어간다.
foo.call(bar, 1, 2, 3); // 이것도...
Function.prototype의 call이나 apply 메소드를 호출하면 this가 무엇을 가리킬지 정해줄 수 있다. 호출할 때 첫 번째 인자로 this가 가리켜야 할 객체를 넘겨준다.
그래서 foo Function 안에서 this는 위에서 설명했던 객체 중 하나를 가리키는 것이 아니라 bar를 가리킨다.
Note: 객체 리터럴에서 this는 그 객체를 가리키지 않는다. 예를 들어
var obj= {me:this}에서me가obj를 가리키는 것이 아니라 위에 설명한 5가지 객체 중 하나를 가리킨다.
this가 Global 객체를 가리키는 것도 잘못 설계된 부분 중 하나다. 괜찮아 보이지만 실제로는 전혀 사용하지 않는다.
Foo.method = function() {
function test() {
// 여기에서 this는 Global 객체를 가리킨다.
}
test();
}
test 에서 this가 Foo를 가리킬 것으로 생각할 테지만 틀렸다. 실제로는 그렇지 않다.
test에서 Foo에 접근하려면 method에 Local 변수를 하나 만들고 Foo를 가리키게 하여야 한다.
Foo.method = function() {
var that = this;
function test() {
// 여기에서 this 대신에 that을 사용하여 Foo에 접근한다.
}
test();
}
that은 this에 접근하기 위해 만든 변수다. closures와 함께 this의 값을 넘기는 데 사용할 수 있다.
메소드를 변수에 할당해 버리기 때문에 Function Aliasing은 JavaScript에서 안된다.
var test = someObject.methodTest;
test();
test는 다른 함수를 호출하는 것과 다름없어서 this가 someObject를 가리키지 않는다.
처음에는 this를 늦게 바인딩하는 것이 나쁜 아이디어라고 생각할 수도 있지만, 이 점이 실제로 prototypal inheritance를 가능케 해준다.
function Foo() {}
Foo.prototype.method = function() {};
function Bar() {}
Bar.prototype = Foo.prototype;
new Bar().method();
Bar 인스턴스에서 method를 호출하면 method에서 this는 바로 그 인스턴스를 가리킨다.