|
| 1 | +# Chapter 22 - `this` |
| 2 | + |
| 3 | +## 1. `this` 키워드 |
| 4 | +`this`는, 자신이 속한 객체 혹은 자신이 생성할 인스턴스를 가리키는 self-referencing variable(자기 참조 변수)다.<br/> |
| 5 | +`this`는 자바스크립트 엔진에 의해 암묵적으로 생성되며, 코드 어디서든 참조할 수 있다. |
| 6 | + |
| 7 | +중요한 점은! `this`가 가리키는 값, 즉 `this` 바인딩은 **함수 호출 방식에 의해 동적으로 결정**된다.<br/> |
| 8 | +예제와 함께 살펴 보자. |
| 9 | + |
| 10 | +```javascript |
| 11 | +// this는 어디서든지 참조 가능하다. |
| 12 | +// 전역에서 this는 전역 객체 window를 가리킨다. |
| 13 | +console.log(this); // window |
| 14 | + |
| 15 | +function square(number) { |
| 16 | + // 일반 함수 내부에서 this는 전역 객체 window를 가리킨다. |
| 17 | + console.log(this); // window |
| 18 | + return number * number; |
| 19 | +} |
| 20 | +square(2); |
| 21 | + |
| 22 | +const person = { |
| 23 | + name: 'Lee', |
| 24 | + getName() { |
| 25 | + // 메서드 내부에서 this는 메서드를 호출한 객체를 가리킨다. |
| 26 | + console.log(this); // {name: "Lee", getName: ƒ} |
| 27 | + return this.name; |
| 28 | + } |
| 29 | +}; |
| 30 | +console.log(person.getName()); // Lee |
| 31 | + |
| 32 | +function Person(name) { |
| 33 | + this.name = name; |
| 34 | + // 생성자 함수 내부에서 this는 생성자 함수가 생성할 인스턴스를 가리킨다. |
| 35 | + console.log(this); // Person {name: "Lee"} |
| 36 | +} |
| 37 | +const me = new Person('Lee'); |
| 38 | +``` |
| 39 | +(참고로 strict mode가 적용된 일반 함수 내부의 `this`에서는 undefined가 바인딩된다. 엄밀히 말하면 일반 함수 내부에선 `this`를 사용할 이유가 없기 때문이다.) |
| 40 | + |
| 41 | +함수 호출 방식에 따라 달라지는 `this` 바인딩은 다음 절에서 더 자세히 살펴 보자. |
| 42 | + |
| 43 | +## 2. 함수 호출 방식과 `this` 바인딩 |
| 44 | +동일한 함수여도 다음과 같이 어떤 방식으로 호출하느냐에 따라 `this`에 바인딩되는 값이 달라진다. 예제와 함께 보자. |
| 45 | +1. 일반 함수 호출 |
| 46 | +2. 메서드 호출 |
| 47 | +3. 생성자 함수 호출 |
| 48 | +4. Function.prototype.apply/call/bind 메서드에 의한 간접 호출 |
| 49 | + |
| 50 | +```javascript |
| 51 | +// this 바인딩은 함수 호출 방식에 따라 동적으로 결정된다. |
| 52 | +const foo = function () { |
| 53 | + console.dir(this); |
| 54 | +}; |
| 55 | + |
| 56 | +// 동일한 함수도 다양한 방식으로 호출할 수 있다. |
| 57 | + |
| 58 | +// 1. 일반 함수 호출 |
| 59 | +// foo 함수를 일반적인 방식으로 호출 |
| 60 | +// foo 함수 내부의 this는 전역 객체 window를 가리킨다. |
| 61 | +foo(); // window |
| 62 | + |
| 63 | +// 2. 메서드 호출 |
| 64 | +// foo 함수를 프로퍼티 값으로 할당하여 호출 |
| 65 | +// foo 함수 내부의 this는 메서드를 호출한 객체 obj를 가리킨다. |
| 66 | +const obj = { foo }; |
| 67 | +obj.foo(); // obj |
| 68 | + |
| 69 | +// 3. 생성자 함수 호출 |
| 70 | +// foo 함수를 new 연산자와 함께 생성자 함수로 호출 |
| 71 | +// foo 함수 내부의 this는 생성자 함수가 생성한 인스턴스를 가리킨다. |
| 72 | +new foo(); // foo {} |
| 73 | + |
| 74 | +// 4. Function.prototype.apply/call/bind 메서드에 의한 간접 호출 |
| 75 | +// foo 함수 내부의 this는 인수에 의해 결정된다. |
| 76 | +const bar = { name: 'bar' }; |
| 77 | +foo.call(bar); // bar |
| 78 | +foo.apply(bar); // bar |
| 79 | +foo.bind(bar)(); // bar |
| 80 | +``` |
| 81 | + |
| 82 | +### 2-1. 일반 함수 호출 |
| 83 | +함수를 일반 함수로 호출하면, 함수 내부의 `this`에는 Global object가 바인딩된다. (e.g., `window`)<br/> |
| 84 | +그 어떤 함수라도(**중첩 함수, 콜백 함수 포함**), 일반 함수로 호출된다면 `this`에는 Global object가 바인딩된다.<br/> |
| 85 | +(단, strict mode가 적용된 일반 함수 내부의 `this`에는 `undefined`가 바인딩된다.) |
| 86 | + |
| 87 | +이런 자바스크립트의 특징은 보통의 경우 문제가 되기 때문에,<br/> |
| 88 | +중첩 함수나 콜백 함수 내부의 `this` 바인딩을 메서드의 `this`와 일치시키기 위한 여러 방법이 존재한다. |
| 89 | +* Function.prototype.apply/call/bind 메서드를 활용해 명시적으로 `this`를 바인딩하거나, |
| 90 | +* 화살표 함수를 이용해 `this` 바인딩을 일치시킬 수도 있다. |
| 91 | + |
| 92 | +### 2-2. 메서드 호출 |
| 93 | +메서드 내부의 `this`에는 그 메서드를 호출한 객체가 바인딩된다.<br/> |
| 94 | +메서드 내부의 `this`는 그 메서드 객체를 가리킬 것처럼 보일 수도 있겠지만 아니다. (메서드란 것은 프로퍼티에 바인딩된, 엄연히 독립적인 함수이자 객체이기 때문에 그렇게 오해할만함)<br/> |
| 95 | +메서드 내부의 `this`는 메서드를 가리키는 객체와는 관계가 없고, **그 메서드를 호출한 객체에 바인딩된다는 사실을 유념하자.** |
| 96 | + |
| 97 | +### 2-3. 생성자 함수 호출 |
| 98 | +생성자 함수 내부의 `this`에는 생성자 함수가 (미래에) 생성**할** 인스턴스가 바인딩된다. |
| 99 | + |
| 100 | +### 2-4. Function.prototype.apply/call/bind 메서드에 의한 간접 호출 |
| 101 | +(apply, call 메서드 내용은 생략)<br/> |
| 102 | +**bind 메서드**는 메서드의 `this`와 메서드 내부의 중첩 함수 또는 콜백 함수의 `this`가 불일치하는 문제를 해결하기 위해 유용하게 사용된다.<br/> |
| 103 | +예제와 함께 살펴 보자. |
| 104 | + |
| 105 | +```javascript |
| 106 | +const person = { |
| 107 | + name: 'Lee', |
| 108 | + foo(callback) { |
| 109 | + // bind 메서드로 callback 함수 내부의 this 바인딩을 전달 |
| 110 | + setTimeout(callback.bind(this), 100); |
| 111 | + } |
| 112 | +}; |
| 113 | + |
| 114 | +person.foo(function () { |
| 115 | + console.log(`Hi! my name is ${this.name}.`); // Hi! my name is Lee. |
| 116 | +}); |
| 117 | +``` |
| 118 | + |
| 119 | + |
| 120 | +**⭐최종 정리⭐** <br/> |
| 121 | +<img src="https://github.com/user-attachments/assets/54e5612d-ca38-4045-95b8-d3a9631e0a55" width="60%" /> |
| 122 | + |
| 123 | +끝. |
0 commit comments