this란
- 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기참조변수다.
this
를 통해 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티나 메소드를 참조할 수 있다.
this
를 지역 변수처럼 사용할 경우 this
바인딩은 함수 호출 방식에 의해 동적으로 결정된다.
객체 리터럴, 생성자 함수
- 객체 리터럴 메소드 내부에서의
this
는 메소드를 호출한 객체를 가리킨다.
const circle = {
r: 5,
getDiameter() {
return 2 * this.r;
}
}
console.log(circle.getDiameter()); // 10
- 생성자 함수 내부의
this
는 생성자 함수가 생성할 인스턴스를 가리킨다.
function Circle(r) {
this.r = r;
}
Circle.prototype.getDiameter = function() {
return 2 * this.r;
}
const circle = new Circle(5);
console.log(circle.getDiameter()); // 10
호출되는 방식에 따라 바뀌는 this
console.log(this); // window
// 일반 함수 내부에서의 this는 window를 바인딩
function test(n) {
console.log(this); // window
return n;
}
test(5);
// 메소드 내부에서 this는 메소드를 호출한 객체를 바인딩
const test2 = {
name: 'test',
getName() {
console.log(this); // {name: "test", getName: f}
return this.name;
}
}
console.log(test2.getName()); // test
// 생성자 함수 내부에서 this는 생성자 함수가 생성할 인스턴스를 바인딩
function Test(name) {
this.name = name;
console.log(this); // Test {name: "test"}
}
const t = new Test("test");
함수 호출 방식에 따른 this바인딩
- this 바인딩은 함수 호출방식에 따라 동적으로 결정된다.
const test = functuin() {
console.log(this);
}
test(); // 1. 일반 함수 호출: window 바인딩
const obj = { test };
obj.test(); // 2. 메소드 호출: obj 바인딩
new test(); // 3. 생성자 함수 호출: 생성자 함수가 생성한 인스턴스 바인딩
const bar = { name: 'bar' }; // 4. call, apply, bind 메소드에 의한 간접 호출: 인수에 의해 결정
test.call(bar); // bar 바인딩
test.apply(bar); // bar 바인딩
test.bind(bar)(); // bar 바인딩
일반 함수 호출
var value = 1;
const obj = {
value: 100,
test() {
console.log(this); // {value: 100, test: f}
console.log(this.value); // 100
function test2() {
console.log(this) // window
console.log(this.value) // 1
}
test2() // 중첩 함수라도 일반 함수로 호출되면 전역 객체가 바인딩
}
};
obj.test();
- 일반 함수로 호출된 모든 함수 내부의
this
는 전역 객체가 바인딩 된다.
메소드 호출
const test = {
name: "te",
getName() {
return this.name; // 메소드 내부의 this는 메소드를 호출한 객체에 바인딩
}
}
console.log(test.getName()); // te
생성자 함수 호출
- 생성자 함수 내부의
this
에는 생성자 함수가 생성할 인스턴스가 바인딩된다.
function Circle(r) {
this.r = r;
this.getDiameter = function() {
return 2 * this.r;
};
}
const circle1 = new Circle(5);
const circle2 = new Circle(10);
console.log(circle1.getDiameter()); // 10
console.log(circle2.getDiameter()); // 20
apply/call/bind 메소드에 의한 간접 호출
function getThisBinding() {
return this;
}
const thisArg = { a: 1 };
console.log(getThisBinding()); // windiw
console.log(getThisBinding.apply(thisArg)); // {a: 1}
console.log(getThisBinding.call(thisArg)); // {a: 1}
console.log(getThisBinding.apply(thisArg, [1, 2, 3])); // {a: 1}
console.log(getThisBinding.call(thisArg, 1, 2, 3)); // {a: 1}
// aplly, call의 메소드는 함수를 호출하면서 첫 번째 인수로 전달한 특정 객체를 호출한 함수의 this에 바인딩
console.log(getThisBinding.bind(thisArg)); // getThisBinding
console.log(getThisBinding.bind(thisArg)()); // {a: 1}
// bind는 함수를 호출하지 않고, 첫 번째 인수로 전달한 값으로 this 바인딩이 교체된 함수를 새롭게 생성하여 반환한다.
결론
- 일반 함수 호출: 전역 객체
- 메소드 호출: 메소드를 호출한 객체
- 생성자 함수 호출: 생성자 함수가 생성할 인스턴스
- apply/call/bind 메소드에 의한 간접 호출: 메소드에 첫 번째 인수로 전달한 객체