this는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수다. this를 통해 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티나 메서드를 참조할 수 있다.
// 전역에서의 this는 window를 가리킨다.
console.log(this); // window
function foo(number) {
// 일반 함수 내부에서 this는 전역 객체 window를 가리킨다.
console.log(this); // window
return number * 2
}
const person = {
name: 'kang',
getName() {
// 메서드 내부에서 this는 메서드를 호출한 객체를 가리킨다.
console.log(this); // {name: "kang", getName: f}
return this.name;
}
}
function Person(name) {
this.name = name;
// 생성자 함수 내부에서 this는 생성자 함수가 생성할 인스턴스를 가리킨다.
console.log(this); // Person {name: 'kang'}
}
자바스크립트의 this는 함수가 호출되는 방식에 따라 this에 바인딩될 값이 동적으로 결정된다.
// 전역변수 value
var value = 1;
const obj = {
value: 100,
foo() {
console.log(this); // {value: 100, foo: f}
console.log(this.value); // 100
// 메서드내에서 정의한 중첩함수
function bar() {
console.log(this); // window
console.log(this.value); // 1
}
setTimeout(function() {
console.log(this); // window
},100)
}
// 메서드 내에서 정의한 중첩 함수도 일반함수로 호출되면 함수 내부의 this는 window가 바인딩 된다.
bar();
};
obj.foo();
메서드 내에서 정의한 중첩 함수도 일반 함수로 호출되면 함수 내부의 this는 window가 바인딩된다. 만약 콜백 함수가 일반 함수로 호출된다면 콜백 함수의 내부 this에도 전역 객체가 바인딩된다. 하지만 메서드 내에서 정의한 중첩 함수 또는 메서드에게 전달한 콜백 함수(보조 함수)가 일반 함수로 호출될 때 메서드 내의 중첩 함수 또는 콜백 함수의 this가 전역 객체를 바인딩하는 것은 문제가 있다.
// 전역변수 value
var value = 1;
const obj = {
value: 100,
foo() {
// this 바인딩(obj)을 변수 that에 할당한다
const that = this;
setTimeout(function() {
console.log(that.value); // 100
},100)
}
};
obj.foo();
이렇게 that 이란 변수에 obj를 바인딩시켜서 사용하면 된다. 이 방법 외에도 this를 명시적으로 바인딩할 수 있는 Function.prototype.apply, Function.prototype.call, Function.prototype.bind메서드를 제공한다.
// 전역변수 value
var value = 1;
const obj = {
value: 100,
foo() {
// 콜백함수에 명시적으로 this를 바인딩 한다.
setTimeout(function() {
console.log(this.value); // 100
}.bind(this),100)
// 또는 화살표 함수로 바인딩할 수 있다.
// 화살표 함수 내부의 this는 상위 스코프의 this를 가리킨다.
setTimeout(() => console.log(this.value), 100); // 100
}
};
obj.foo();
bind, 및 화살표 함수를 이용하여 바인딩할 수 있다. 화살표 함수 내부 this는 상위 스코프의 this를 가리킨다.
메서드 호출
메서드 내부의 this에는 메서드를 호출한 객체가 바인딩된다. 주의할 점은 메서드를 소유한 객체가 아닌 호출한 객체에 바인딩된다는 것이다.
const person = {
name: 'Kang',
getName() {
return this.name;
}
};
const anotherPerson = {
name: 'Kim'
};
// getName 메서드를 anotherPerson 객체의 메서드로 할당
anotherPerson.getName = person.getName;
// getName 메서드를 호출한 객체는 anotherPerson 이다.
console.log(anotherPerson.getName()); // Kim
// 메서드를 변수에 할당
const getName = person.getName;
// getName을 일반 함수로 호출
console.log(getName()); // ''
// 일반 함수로 호출되면 getName의 this는 window가 되므로, window.name과 같다.
생성자 함수 호출
생성자 함수 내부의 this에는 생성자 함수가 (미래에) 생성할 인스턴스가 바인딩된다.
function Circle(radius) {
// 생성자 내부의 this는 생성자 함수가 생성할 인스턴스를 가리킨다.
this.radius = radius;
this.getDiameter = function() {
return 2 * this.radius;
};
}
const circle1 = new Circle(5);
const circle2 = new Circle(10);
console.log(circle1.getDiameter()); // 10
console.log(circle2.getDiameter()); // 20
Function.prototype.apply / call / bind 메서드에 의한 간접 호출
apply / call / bind 메서드는 Function.prototype의 메서드다. 즉 이 메서드는 모든 함수가 상속받아 사용 가능하다.
/**
* 주어진 this 바인딩과 인수 리스트 배열을 사용하여 함수를 호출 한다.
* @param thisArg - this로 사용할 객체
* @param argsArray - 함수에게 전달할 인수 리스트의 배열 또는 유사 배열 객체
* @return 호출된 함수의 반환 값
*/
Function.prototype.apply(thisArg[, argsArray]);
/**
* 주어진 this 바인딩과 , 로 구분된 인수 리스트를 사용하여 함수를 호출한다.
* @param thisArg - this로 사용할 객체
* @param args1, args2, ... - 함수에게 전달할 인수 리스트
* @return 호출된 함수의 반환 값
*/
Function.prototype.call(thisArg[, args1[,args2[,...]]]);
apply와 call 메서드의 본질적인 기능은 함수를 호출하는 것이다. 함수를 호출하면서 첫 번째 인수로 전달한 특정 객체를 호출한 함수의 this에 바인딩 한다. 둘의 차이점은 인수를 전달하는 방식만 다를뿐 동일하게 동작한다. 대표적인 용도는 argumetns 객체와 같은 유사 배열 객체에 배열 메서드를 사용하는 경우다. argumetns 객체는 배열이 아니기 때문에 Array.prototype.slice 같은 배열의 메서드를 사용할 수 없으나 apply, call 이용하면 가능하다.
function convertArgsToArray() {
console.log(arguments);
// Array.prototype.slice.call 를 인수없이 호출하면 배열의 복사본을 생성한다.
const arr = Array.prototype.slice.call(arguments);
console.log(arr);
return arr;
}
convertArgsToArray(1,2,3); // [1,2,3]
bind 메서드는 apply 와 call과 달리 함수를 호출하지는 않고 this로 사용할 객체만 전달한다. 그러기 때문에 그 함수에 대해 명시적으로 호출해야 한다. bind 메서드는 메서드의 this와 내부의 중첩 함수 또는 콜백 함수의 this가 불일치하는 문제를 해결할 때 유용하게 사용된다.
const person = {
name: 'Kang',
foo(callback) {
// bind를 하지 않았다면 콜백함수가 일반 함수로서 호출되었기 때문에 this는 window를 가리켰을 것이다.
setTimeout(callback.bind(this),100);
}
};
person.foo(function() {
console.log(this.name); // Kang
});
이를 총 정리해보면 다음과 같다.
함수 호출 방식 | this 바인딩 |
일반 함수 호출 | 전역 객체 |
메서드 호출 | 메서드를 호출한 객체 |
생성자 함수 호출 | 생성자 함수가 (미래에) 생성할 인스턴스 |
call / apply / bind 호출 | 첫번째 인수로 전달된 객체 |
'Javascript' 카테고리의 다른 글
Number & Math (0) | 2020.11.24 |
---|---|
클로저 (0) | 2020.11.18 |
빌트인 객체 (0) | 2020.11.18 |
프로토타입 (0) | 2020.11.16 |
생성자 함수에 의한 객체 생성 (0) | 2020.11.16 |
댓글