자바스크립트에서 모든 함수는 실행될 때 마다 함수 내부에
this
라는 객체가 추가된다.
arguments
라는 유사 배열 객체와 함께 함수 내부로 암묵적으로 전달되는 것이다.
그렇기 때문에 자바스크립트에서의this
는 함수가 호출된 상황에 따라 그 모습을 달리한다.
객체의 프로퍼티가 함수일 경우 메소드라고 칭한다. this
는 함수를 실행할 때, 함수를 소유하고 있는 객체(메소드를 포함하고 있는 인스턴스)를 참조한다.
즉, 해당 메소드를 호출한 객체로 바인딩(binding
)된다.
예를 들어, A.B
를 호출할 때 B
함수 내부에서의 this
는 A
를 가리킨다.
var myObject = {
name: "foo",
sayName: function() {
console.log(this);
}
};
myObject.sayName();
위 코드는 Object {name: "foo", sayName: sayName()}
를 출력한다.
특정 객체의 메소드가 아니라 함수를 호출할 경우, 해당 함수 내부 코드에서 사용된 this는 전역객체에 바인딩(binding
)된다.
예를 들어, A.B
를 호출할 때 A
가 전역 객체가 되므로 B
함수 내부에서의 this
는 자명하게도 전역 객체에 바인딩(binding
) 되는 것이다.
var value = 100;
var myObj = {
value: 1,
func1: function() {
console.log(`func1's this.value: ${this.value}`);
var func2 = function() {
console.log(`func2's this.value ${this.value}`);
};
func2();
}
};
myObj.func1();
func1
에서의 this
는 상황 1과 같다. 그렇기 때문에myObj
가 this
로 바인딩되고 myObj
의 value
인 1이 콘솔에 출력된다.
그러나 func2
는 상황 2로 해석된다. A.B
구조에서 A
가 없기 때문에, 함수 내부에서 this
가 전역 객체를 참조하게 되고 value
는 100이 되는 것이다.
위 코드는,
func1's this.value: 1 func2's this.value: 100
를 출력한다.
단순히 함수를 호출하는 것이 아닌, new 키워드를 통해 생성자 함수를 호출할 경우 this
는 또 다르게 바인딩 된다.
new 키워드를 통해서 호출된 함수 내부에서의 this
는 객체 자신을 의미한다.
생성자 함수를 호출할 때의 this
바인딩은 생성자 함수가 동작하는 방식을 통해 이해할 수 있다.
new
연산자를 통해 함수를 생성자로 호출하게 되면, 일단 빈 객체가 생성되고 this
가 바인딩 된다.
이 객체는 함수를 통해 생성된 객체이며, 자신의 부모인 프로토타입 객체와 연결되어 있다. 그리고 return
문이 명시되어 있지 않은 경우에는 this
로 바인딩 된 새로 생성한 객체가 반환된다.
var Person = function(name) {
console.log(this);
this.name = name;
};
var foo = new Person("foo"); // Person
console.log(foo.name); // foo
이제까지 살펴본 상황1, 상황2, 상황3 에 의존하지 않고 this
를 자바스크립트 코드로 주입 또는 설정할 수 있다.
상황 2에서 사용했던 예제 코드를 다시 한번 살펴보자. func2
를 호출할 때, func1
에서의 this
를 주입하기 위해서 위 세가지 메소드를 사용할 수 있다.
그리고 세 메소드의 차이점을 파악하기 위해 func2
에 파라미터를 받을 수 있도록 수정하자.
var value = 100;
var myObj = {
value: 1,
func1: function() {
console.log(`func1's this.value: ${this.value}`);
var func2 = function(val1, val2) {
console.log(`func2's this.value ${this.value} and ${val1} and ${val2}`);
}.bind(this, `param1`, `param2`);
func2();
}
};
myObj.func1();
// console> func1's this.value: 1
// console> func2's this.value: 1 and param1 and param2
var value = 100;
var myObj = {
value: 1,
func1: function() {
console.log(`func1's this.value: ${this.value}`);
var func2 = function(val1, val2) {
console.log(`func2's this.value ${this.value} and ${val1} and ${val2}`);
};
func2.call(this, `param1`, `param2`);
}
};
myObj.func1();
// console> func1's this.value: 1
// console> func2's this.value: 1 and param1 and param2
var value = 100;
var myObj = {
value: 1,
func1: function() {
console.log(`func1's this.value: ${this.value}`);
var func2 = function(val1, val2) {
console.log(`func2's this.value ${this.value} and ${val1} and ${val2}`);
};
func2.apply(this, [`param1`, `param2`]);
}
};
myObj.func1();
// console> func1's this.value: 1
// console> func2's this.value: 1 and param1 and param2
bind
bind
는 함수를 선언할 때, this
와 파라미터를 지정해줄 수 있다.apply
apply
는 함수를 호출할 때 this
와 파라미터를 지정해준다.apply
메소드에는 첫 번째 인자로 this
를 넘겨주고 두 번째 인자로 넘겨줘야 하는 파라미터를 배열의 형태로 전달한다.call
call
은 함수를 호출할 때 this
와 파라미터를 지정해준다.