Skip to content

Commit 3e221be

Browse files
authored
Merge branch 'ahnlab-220:main' into main
2 parents 5601344 + 5df4233 commit 3e221be

5 files changed

Lines changed: 1526 additions & 1 deletion

File tree

book/_toc.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,13 @@ parts:
6565
- file: 이용우/chapter_15
6666
- file: 이용우/chapter_16
6767
- file: 이용우/chapter_17
68-
- file: 이용우/chapter_18
68+
- file: 이용우/chapter_18
69+
- file: 이용우/chapter_19
70+
- file: 이용우/chapter_20
71+
- file: 이용우/chapter_21
72+
- file: 이용우/chapter_22
73+
- file: 이용우/chapter_23
74+
- file: 이용우/chapter_24
75+
- file: 이용우/chapter_25
76+
- file: 이용우/chapter_26
77+

book/공희재/chapter_26.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,181 @@
11
# Chapter 26 - ES6 함수의 추가 기능
2+
## 1. 함수의 구분
3+
ES6 이전까지 자바스크립트의 함수는 별다른 구분 없이 다양한 목적으로 사용되었다.<br/>
4+
이는 편리한 것 같지만 실수를 유발시킬 수 있으며 성능 면에서도 손해다. 예제를 살펴 보자.
5+
```javascript
6+
var foo = function() {
7+
return 1;
8+
};
9+
10+
// 일반적인 함수로 호출
11+
foo(); // -> 1
12+
13+
// 생성자 함수로 호출
14+
new foo(); // -> foo {}
15+
16+
// 메서드로 호출
17+
var obj = { foo: foo };
18+
obj.foo(); // -> 1
19+
```
20+
21+
ES6 이전의 모든 함수는 사용 목적에 따라 명확한 구분이 없으므로<br/>
22+
호출 방식에 특별한 제약이 없고 생성자 함수로 호출되지 않아도 프로토타입 객체를 생성한다.<br/>
23+
자바스크립트 함수의 이러한 특징은 이해하기 혼란스럽고, 프로그램 성능에도 좋지 않다.
24+
25+
이러한 문제를 해결하기 위해, **ES6에서는 함수를 사용 목적에 따라 세 가지 종류로 구분**해 정의했다.
26+
27+
|**ES6 함수의 구분**|`constructor`|`prototype`|`super`|`arguments`|
28+
|-|-|-|-|-|
29+
|**일반 함수(Normal)**|O|O|X|O|
30+
|**메서드(Method)**|X|X|O|O|
31+
|**화살표 함수(Arrow)**|X|X|X|X|
32+
33+
일반 함수는 constructor이지만, ES6의 메서드와 화살표 함수는 non-constructor이다. 다음 절에서 더 자세히 살펴 보자.
34+
35+
## 2. ES6 Methods: 메서드
36+
ES6 사양에서는 메서드에 대한 정의가 명확하게 규정되었다: **메서드 축약 표현으로 정의된 함수만이 '메서드'다.**
37+
```javascript
38+
const obj = {
39+
x: 1,
40+
foo() { return this.x; }, // ✅ foo는 '메서드'다.
41+
bar: function() { return this.x; } // ❌ bar는 '메서드'가 아닌 일반 함수다.
42+
};
43+
```
44+
45+
ES6에서 정의한 '**메서드**'는, 인스턴스를 생성할 수 없는 non-constructor이다. 따라서 생성자 함수로서 호출할 수 없게 된다.<br/>
46+
ES6 메서드는 인스턴스를 생성할 수 없으므로 prototype 프로퍼티가 없고 프로토타입도 생성하지 않는다.<br/>
47+
또한, ES6 메서드는 자신을 바인딩한 객체를 가리키는 슬롯 `[[HomeObject]]`를 갖기 때문에, `super` 키워드를 사용할 수 있다.
48+
49+
이처럼 ES6 메서드는 본연의 기능인 `super`를 추가하고, 의미적으로 맞지 않는 기능인 constructor는 제거했다.
50+
51+
## 3. Arrow Functions: 화살표 함수
52+
화살표 함수는, 기존의 함수와 비교해 표현만 간략한 게 아니라 **내부 동작도 간략**하다.<br/>
53+
특히, 화살표 함수는 콜백 함수 내부에서 **`this`가 전역 객체를 가리키는 문제를 해결**한다.
54+
55+
### 3-1. 화살표 함수 정의
56+
생략. 책을 참고합시다~
57+
58+
### 3-2. 화살표 함수와 일반 함수의 차이
59+
1. 화살표 함수는 인스턴스를 생성할 수 없는 **non-constructor**이다.
60+
2. 화살표 함수는 중복된 매개변수 이름을 선언할 수 없다.
61+
3. 화살표 함수는 함수 자체의 `this`, `arguments`, `super`, `new.target` 바인딩을 **갖지 않는다**.
62+
63+
### 3-3. `this`
64+
화살표 함수의 `this`는 일반 함수의 그것과 다르게 동작한다. 이건 의도된 설계다:<br/>
65+
**콜백 함수 내부의 `this`가, 외부 함수의 `this`와 달라 혼란을 발생시키는 문제를 해결하기 위함**이다.
66+
67+
22장에서 배웠듯이 `this`의 값은 함수가 어떻게 호출됐는지에 따라 다르게 바인딩된다.<br/>
68+
자바스크립트의 이러한 특징은, **콜백 함수를 일반 함수 형태로 호출할 때 골치 아파진다**.<br/>
69+
일반 함수로 호출하는 모든 함수의 내부에는 `this`가 전역 객체를 가리키지만,<br/>
70+
그 함수가 만약 클래스 내부라면 `undefined`를 바인딩하게 된다.<br/>
71+
클래스 내부의 모든 코드에는 strict mode가 적용되는 영향을 받기 때문이다.
72+
```javascript
73+
// ❌ Wrong Practice!! ❌
74+
class Prefixer {
75+
constructor(prefix) {
76+
this.prefix = prefix;
77+
}
78+
79+
add(arr) {
80+
return arr.map(function (item) {
81+
return this.prefix + item; // TypeError: Cannot read property 'prefix' of undefined
82+
});
83+
}
84+
}
85+
```
86+
87+
이런 문제를 우리는 **콜백 함수 내부의 `this` 문제**라고 부른다.<br/>
88+
ES6에서는, 콜백 함수 내부의 `this` 문제를 해결하기 위해 화살표 함수를 제안한다.
89+
90+
```javascript
91+
// ✅ 위 예제를 화살표 함수로 해결 ✅
92+
class Prefixer {
93+
constructor(prefix) {
94+
this.prefix = prefix;
95+
}
96+
97+
add(arr) {
98+
return arr.map(item => this.prefix + item);
99+
}
100+
}
101+
```
102+
103+
화살표 함수는 함수 자체의 `this` 바인딩을 갖지 않는다.<br/>
104+
따라서 **화살표 함수 내부에서 `this`를 참조하면 상위 스코프의 `this`를 그대로 참조**한다.
105+
106+
우리는 이를 **Lexical This**라고 부른다.<br/>
107+
Lexical this는 마치 렉시컬 스코프처럼, 화살표 함수의 `this`**함수가 정의된 위치에 의해 결정**되는 `this`임을 의미한다.
108+
109+
한 가지 유의할 점은 객체 내 메서드를 정의할 땐 화살표 함수를 사용하지 않아야 한다는 점이다.
110+
```javascript
111+
// ❌ Wrong Practice!! ❌
112+
const person = {
113+
name: 'Lee',
114+
sayHi: () => console.log(`hey ${this.name}`)
115+
};
116+
```
117+
위 예제가 틀린 이유는, sayHi 프로퍼티에 할당한 화살표 함수의 `this`는,<br/>
118+
메서드를 호출한 객체인 person을 가리키는 게 아니라, 상위 스코프인 전역 객체를 가리키기 때문이다.
119+
120+
따라서 **객체의 메서드를 정의할 땐** 아래처럼 ES6 메서드 축약 표현으로 정의한 **ES6 메서드**를 사용하는 것이 좋다.
121+
```javascript
122+
// ✅ 위 예제를 해결 ✅
123+
const person = {
124+
name: 'Lee',
125+
sayHi() {
126+
console.log(`hey ${this.name}`);
127+
}
128+
};
129+
```
130+
131+
### 3-4. `super`
132+
화살표 함수는 함수 자체의 super 바인딩을 갖지 않는다.<br/>
133+
따라서 화살표 함수 안에서 `super`를 참조하면, `this`가 동작하는 것과 마찬가지로 상위 스코프의 `super`를 참조한다.
134+
```javascript
135+
class Base {
136+
constructor(name) {
137+
this.name = name;
138+
}
139+
140+
sayHi() {
141+
return `Hi! ${this.name}`;
142+
}
143+
}
144+
145+
class Derived extends Base {
146+
sayHi = () => `${super.sayHi()} how are you doing?`;
147+
}
148+
149+
const derived = new Derived('Lee');
150+
console.log(derived.sayHi()); // Hi! Lee how are you doing?
151+
```
152+
153+
### 3-5. `arguments`
154+
마찬가지로 화살표 함수는 함수 자체의 arguments 바인딩을 갖지 않는다.<br/>
155+
따라서 화살표 함수 안에서 `arguments`를 참조하면, `this`가 동작하는 것과 마찬가지로 상위 스코프의 `arguments`를 참조한다.
156+
157+
이처럼 **화살표 함수에서 가변 인자 함수**를 구현해야 할 때는<br/>
158+
(`arguments`를 쓰지 못하므로) 반드시 **Rest 파라미터**를 사용해야 한다.
159+
160+
## 4. Rest 파라미터
161+
### 4-1. 기본 문법
162+
Rest 파라미터는 아래처럼 함수에 전달된 인수들의 목록을 **배열**로 받는다.<br/>
163+
Rest 파라미터는 단 하나만 선언할 수 있으며, 다른 일반 매개변수와 섞어 쓸 수 있다.
164+
```javascript
165+
function foo(param, ...rest) {
166+
console.log(param); // 1
167+
console.log(rest); // [2, 3, 4, 5]
168+
}
169+
170+
foo(1, 2, 3, 4, 5);
171+
```
172+
173+
### 4-2. Rest 파라미터와 `arguments` 객체
174+
Rest 파라미터와 `arguments` 객체 간 가장 큰 차이점은 바로 배열이냐 아니냐에 있다.<br/>
175+
`arguments` 객체는 유사 배열 객체이므로 반드시 배열로 변환해야만 배열 메서드를 사용할 수 있는 반면,<br/>
176+
**Rest 파라미터는 배열**이므로 `map`이나 `filter` 같은 배열 메서드를 곧바로 사용할 수 있다.
177+
178+
## 5. 매개변수 기본값
179+
생략. 책을 참고합시다~!
180+
181+
끝.

0 commit comments

Comments
 (0)