this는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수이다.
this가 가리키는 값, 즉 this 바인딩은 함수 호출 방식에 의해 동적으로 결정된다.
함수를 호출하는 방식에는 다음과 같은 4가지가 있다.
Function.prototype.call/apply/bind 메서드에 의한 간접 호출일반 함수의
this는 기본적으로window다.
(function foo() {
console.log(this);
})();
위 코드를 브라우저에서 실행했을 시 결과는 window이다.
다만, 일반 함수의 경우 객체를 생성하지 않기 때문에 일반적으로 this는 여기서 의미가 없다. 따라서 strict mode가 적용된 일반 함수에서의 this는 undefined가 된다.
(참고로 node.js 환경에서 위 코드를 똑같이 실행했을 때 결과는 window가 아닌 global이 나오게 된다.)
메서드 내에서 정의한 중첩 함수, 그리고 콜백 함수 또한 일반 함수로 호출될 경우 마찬가지로 내부의 this는 전역 객체가 바인딩된다. 그러나 두 함수의 경우 일반적으로 외부 함수를 돕는 헬퍼 함수의 역할을 하기 때문에 외부 함수의 this와 서로 일치하지 않는다는 점은 헬퍼 함수로 동작하기 어렵게 만든다.
따라서 외부 함수와 this를 일치시키기 위해서는
this를 변수에 저장하여 헬퍼 함수에게 전달Function.prototype.call/apply/bind 메서드로 this를 명시적으로 바인딩this 바인딩 일치방식을 이용해야 한다.
메서드 호출 시
this는 메서드를 호출한 객체가 바인딩된다.
const person = {
name: 'bear',
age: 24,
sayName() {
return this.name;
}
}
console.log(person.sayName()); // bear
sayName 메서드의 경우 프로퍼티에 바인딩된 함수이므로 다른 객체의 프로퍼티에 할당하여 다른 객체의 메서드가 될 수도 있고 일반 변수에 할당하여 일반 함수로 호출될 수 있다.
const anotherPerson = {
name: "Kim"
};
anotherPerson.sayName = person.sayName;
// 이 때 sayName 메서드를 호출한 객체는 anotherPerson이다.
console.log(anotherPerson.sayName());
const sayName = person.sayName;
// 일반 함수로 호출하면 this는 window
// window.name은 브라우저 창의 이름을 나타내는 빌트인 프로퍼티로 기본값은 ''이다.
console.log(sayName()); // ''
이를 통해 메서드 내부의 this는 메서드를 가리키고 있는 객체와는 관계가 없고 메서드를 호출한 객체에 바인딩된다는 사실을 다시 한번 확인할 수 있다.
생성자 함수 내부의
this에는 생성자 함수가 (미래에) 생성할 인스턴스가 바인딩된다.
function Human(name) {
this.name = name;
}
const human = new Human('bear');
console.log(human.name); // bear
new 연산자와 함께 호출하지 않으면 생성자 함수가 아니라 일반 함수로 동작한다는 점을 주의하자.
프로토타입 메서드 내부에서 사용된
this도 일반 메서드와 마찬가지로 해당 메서드를 호출한 객체에 바인딩된다.function Human(name) { this.name = name; } Human.prototype.sayName = function() { return this.name; }; const me = new Human("Lee"); Human.prototype.name = "Kim"; console.log(me.sayName()); // ① console.log(Human.prototype.sayName()); // ②①의 경우
getName메서드를 호출한 객체는me다. 따라서this가me이므로this.name은Lee다.
②의 경우getName메서드를 호출한 객체는Human.prototype이다. 여기에name: 'Kim'을 할당하였기 때문에this.name은Kim이다.
Function.prototype.call/apply/bind 메서드에 의한 간접 호출function sayName() {
console.log(arguments);
return this.name;
}
sayName();
앞에서 설명했다시피, 일반적인 함수의 this는 window이다.
이 때 Function.prototype.call/apply/bind 메서드를 통해 함수의 this를 변경할 수 있다.
sayName.call({ name: 'bear' }, 1, 2, 3)
this를 { name: 'bear' }로 변경하고, 인수 리스트를 사용해 함수를 호출한다.
sayName.apply({ name: 'bear' }, [1, 2, 3])
this를 { name: 'bear' }로 변경하고, 인수 배열을 사용해 함수를 호출한다.
sayName.bind({ name: 'bear' })()
this를 { name: 'bear' }로 변경하고, apply/call 메서드와 달리 함수를 호출하지 않고 인수 없이 this로 사용할 객체만 전달한다.
this는 무조건 호출 시에 결정된다.
obj.method()/new키워드 /call/apply/bind키워드를 제외한 나머지 일반 함수의 경우this는 기본적으로window(node의 경우global)