어쩌면 C를 처음 배울 때 포인터에서 느끼는 벽 이상의 무언가를 느끼게 해주는 존재.
``this``는 포인터는 아니지만 어떤 함수의 컨텍스트를 참조한다는 점에서 유사하기도 하다.
1. this
``this``는 다음과 같은 특징을 가진다.
- 실행 컨텍스트
- ``this``는 함수가 호출될 때 그 함수의 실행 컨텍스트에 따라 값이 결정된다.
이 실행 컨텍스트는 함수가 어떻게 호출되었느냐에 따라 달라진다.
예를 들어, 객체의 메서드로 호출되면 그 객체가 ``this``가 되고,
단순히 함수로 호출되면 전역 객체(``window`` 또는 ``global``)가 ``this``가 된다. - 동적 바인딩
- ``this``는 런타임에 결정되는 동적 바인딩을 사용한다.
``this``가 가리키는 대상은 함수가 호출될 때마다 달라질 수 있다.
이는 ``call()``, ``apply()``, ``bind()``와 같은 함수를 통해 명시적으로 변경할 수 있다. - 포인터와의 차이
- 포인터는 메모리 주소를 직접 가리키며, 특정 데이터의 위치를 직접적으로 참조한다.
반면, ``this``는 특정 데이터나 객체를 가리키는 것이 아니라, 함수가 실행되는 맥락을 참조한다.
이는 일반적으로 객체 자신을 가리키지만, 그 자체로는 메모리 주소를 직접 다루는 것이 아니다.
아래 예시 코드를 통해 ``this``의 동작을 확인할 수 있다.
var obj1 = {
outer: function() {
console.log(this); // (1)
var innerFunc = function() {
console.log(this); // (2), (3)
}
innerFunc();
var obj2 = {
innerMethod: innerFunc
};
obj2.innerMethod();
}
};
obj1.outer();
// 실행 결과
// (1): {outer: ƒ}
// (2): global {global: global, clearImmediate: ƒ, setImmediate: ƒ, clearInterval: ƒ, clearTimeout: ƒ, …}
// (3): {innerMethod: ƒ}
2. call()
``call()`` 메서드는 함수를 호출하면서 ``this`` 값을 특정 객체로 설정할 수 있다.
첫 번째 인자로 ``this``로 사용할 값을 전달하고, 그 뒤의 인자들은 호출할 함수에 전달한다.
function greet(greeting, punctuation) {
console.log(greeting + ', ' + this.name + punctuation);
}
var person = {
name: 'Alice'
};
// call을 사용하여 this를 person 객체로 설정하고 인자를 전달
greet.call(person, 'Hello', '!');
// 출력: "Hello, Alice!"
``greet``는 ``person``을 ``this``로 하여 호출된 것이다.
3. apply()
``apply()`` 메서드는 ``call()``과 비슷하지만, 인자들을 배열로 전달해야 한다는 점에서 차이가 있다.
첫 번째 인자는 ``this``로 사용할 값이고, 두 번째 인자는 함수에 전달할 인자들이 담긴 배열이다.
var numbers = [10, 20, 3, 16, 45];
var max = Math.max.apply(null, numbers);
var min = Math.min.apply(null, numbers);
console.log(max, min);
``apply()``는 배열로 전달된 인자들을 개별 인자들로 나누어 함수에 전달한다.
하지만 일반 배열의 사이즈가 매우 크다면?
매우 많은 양을 일일이 하드코드 할 수 없을 것이다.
이때, Spread Operator를 사용해 더 편하게 해결할 수 있다.
const numbers = [10, 20, 3, 16, 45];
const max = Math.max(...numbers);
const min = Math.min(...numbers);
console.log(max min);
``...``는 배열의 요소들을 펼쳐서(Spread) 일일이 인수로 넣어준 것과 같이 만들어 준다.
4. bind()
``bind()`` 메서드는 this 값을 고정한 새로운 함수를 생성한다.
즉, ``bind()``는 즉시 함수를 호출하지 않고, this 값과 인자를 고정한 새로운 함수를 반환한다.
반환된 함수를 나중에 호출할 수 있다.
function Person(name) {
this.name = name;
}
Person.prototype.greet = function () {
console.log(`Hello, my name is ${this.name}`);
};
const person1 = new Person('Bob');
const greet = person1.greet
greet(); // 출력: "Hello, my name is undefined"
const boundGreet = person1.greet.bind(person1);
boundGreet(); // 출력: "Hello, my name is Bob"
여기서 ``person1.greet.bind(person1)``는 ``this``를 ``person``으로 고정한다.
그리고, ``bind`` 메서드를 적용해서 새로 만든 함수는 ``name`` 프로퍼티에 ‘bound’라는 접두어가 붙는다.
따라서 추적하기가 매우 용이하다.
var func = function (a, b, c, d) {
console.log(this, a, b, c, d);
};
var bindFunc = func.bind({ x:1 }, 4, 5);
// func와 bindFunc의 name 프로퍼티의 차이를 살펴보세요!
console.log(func.name); // func
console.log(bindFunc.name); // bound func
위 예시 코드처럼 ``name``을 출력하게 되면,
``bind``된 메서드는 앞에 ``bound``라는 접두어가 붙는 것을 확인할 수 있다.
5. 정리
- call()
- 함수 호출 시 ``this``를 특정 객체로 설정하고, 인자들을 개별적으로 전달한다. - apply()
- 함수 호출 시 ``this``를 특정 객체로 설정하고, 인자들을 배열로 전달한다. - bind()
- ``this``를 특정 객체로 고정한 새로운 함수를 생성하고, 고정된 인자들을 추가로 설정할 수 있다.
함수는 나중에 호출될 수 있다.
아래의 기본 객체가 있다고 가정하자.
var car = {
brand: 'Toyota',
getBrand: function() {
return this.brand;
}
};
var bike = {
brand: 'Honda'
};
그럼 다음의 사용 예시를 확인할 수 있다.
// call 사용
console.log(car.getBrand.call(bike)); // "Honda"
// apply 사용
console.log(car.getBrand.apply(bike)); // "Honda"
// bind 사용
var getBikeBrand = car.getBrand.bind(bike);
console.log(getBikeBrand()); // "Honda"
셋 다 ``this``에 ``bike``를 넘겨주기 때문에 "Honda"를 리턴하게 된다.
``this``에 대해 확실히 공부해 둘 필요성이 대단히 높다.
JS의 객체지향을 위해서라도 필요한 부분이다.
'Camp > T.I.L.' 카테고리의 다른 글
[TIL #5] 소수 만들기 (0) | 2024.08.22 |
---|---|
[TIL #4] 비동기 (0) | 2024.08.13 |
[KPT 회고] 팀 소개 페이지 미니 프로젝트에 대한 회고 (0) | 2024.08.09 |
[TIL #2] 간단한 API 프록시 서버 구현 (0) | 2024.08.09 |
[TIL #1] 명세 (0) | 2024.08.05 |