Skip to content

Commit 3e2af45

Browse files
[객체로서의 함수와 기명 함수 표현식] 재 리뷰
1 parent 5cbfe56 commit 3e2af45

File tree

1 file changed

+45
-45
lines changed
  • 1-js/06-advanced-functions/06-function-object

1 file changed

+45
-45
lines changed

1-js/06-advanced-functions/06-function-object/article.md

Lines changed: 45 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
함수는 객체입니다.
99

10-
함수는 호출 가능한(callable) '행동 객체'입니다. 호출도 할 수 있고 객체처럼 프로퍼티를 추가/제거하거나 참조를 통해 전달하는 것이 가능하죠.
10+
함수는 호출이 가능한(callable) '행동 객체'라고 이해하면 쉽습니다. 우리는 함수를 호출 할 수 있을 뿐만 아니라 객체처럼 함수에 프로퍼티를 추가·제거하거나 참조를 통해 전달할 수도 있습니다.
1111

1212

1313
## 'name' 프로퍼티
@@ -65,7 +65,7 @@ alert(user.sayHi.name); // sayHi
6565
alert(user.sayBye.name); // sayBye
6666
```
6767

68-
그런데, 객체 메서드 이름은 함수처럼 자동 할당이 되지 않습니다. 적절한 이름을 추론하는 게 불가능한 상황이 있는데, 이때 name 프로퍼티엔 빈 문자열이 저장됩니다. 아래와 같이 말이죠.
68+
그런데 객체 메서드 이름은 함수처럼 자동 할당이 되지 않습니다. 적절한 이름을 추론하는 게 불가능한 상황이 있는데, 이때 name 프로퍼티엔 빈 문자열이 저장됩니다. 아래와 같이 말이죠.
6969

7070
```js run
7171
// 배열 안에서 함수를 생성함
@@ -75,11 +75,11 @@ alert( arr[0].name ); // <빈 문자열>
7575
// 엔진이 이름을 설정할 수 없어서 name 프로퍼티의 값이 빈 문자열이 됨
7676
```
7777

78-
실무에서 대부분의 함수는 이름이 있으므로, 위와 같은 상황은 잘 발생하지 않습니다.
78+
실무에서 대부분의 함수는 이름이 있으므로 위와 같은 상황은 잘 발생하지 않습니다.
7979

8080
## 'length' 프로퍼티
8181

82-
내장 프로퍼티 'length'는 함수 매개변수의 개수를 반환합니다. 예시를 살펴봅시다.
82+
내장 프로퍼티 `length`는 함수 매개변수의 개수를 반환합니다. 예시를 살펴봅시다.
8383

8484
```js run
8585
function f1(a) {}
@@ -91,20 +91,20 @@ alert(f2.length); // 2
9191
alert(many.length); // 2
9292
```
9393

94-
나머지 매개변수는 개수에 포함되지 않는다는 걸 위 예시를 통해 확인해 보았습니다.
94+
위 예시를 통해 나머지 매개변수는 개수에 포함되지 않는다는 사실 또한 확인해 보았습니다.
9595

96-
`length` 프로퍼티는 다른 함수 안에서 동작하는 함수를 [검사(introspection)](https://en.wikipedia.org/wiki/Type_introspection)할 때도 사용됩니다.
96+
한편, `length` 프로퍼티는 다른 함수 안에서 동작하는 함수의 [타입을 검사(type introspection)](https://en.wikipedia.org/wiki/Type_introspection) 할 때도 종종 사용됩니다.
9797

98-
아래 예시에서 함수 `ask`질문에 쓰일 `question`조건에 따라 호출할 임의의 수의 `handler` 함수도 함께 받고 있습니다.
98+
질문에 쓰일 `question`질문에 대한 답에 따라 호출할 임의의 수의 `handler` 함수를 함께 받는 함수 `ask`를 예시로 이에 대해 알아봅시다.
9999

100-
사용자가 답을 제출하면 함수는 핸들러 함수를 호출하죠. 아래 예제에선 두 종류의 핸들러 함수를 `ask` 함수에 전달하였습니다.
100+
사용자가 답을 제출하면 `ask` 핸들러 함수를 호출합니다. 이때 우리는 두 종류의 핸들러 함수를 `ask`에 전달할 수 있습니다.
101101

102-
- 인수가 없는 함수: 사용자가 OK를 클릭했을 때 호출되는 함수
103-
- 인수가 있는 함수: 사용자가 OK를 클릭하든, Cancel을 클릭하든 답을 반환하는 함수
102+
- 인수가 없는 함수로, 사용자가 OK를 클릭했을 때만 호출됨
103+
- 인수가 있는 함수로, 사용자가 OK를 클릭하든 Cancel을 클릭하든 호출됨
104104

105-
`handler.length` 프로퍼티를 확인하면 의도한 대로 `handler`를 호출할 수 있습니다.
105+
그리고 `handler.length` 프로퍼티를 사용하면 상황에 맞는 `handler`를 호출할 수 있습니다.
106106

107-
`handler.length` 프로퍼티를 사용하면 인수가 없는 간단한 핸들러 함수(긍정적인 상황에서 호출)와 일반적인 핸들러 함수(조건에 관계없이 호출)를 동시에 구현할 수 있습니다.
107+
사용자가 긍정적인 대답을 했을 때 사용 할 인수가 없는 핸들러를 하나 만들고, 사용자의 응답 종류와 관계없이 범용적으로 사용할만한 핸들러도 구축해 `ask` 내부에서 `handler.length`와 함께 사용하면 되죠.
108108

109109
```js run
110110
function ask(question, ...handlers) {
@@ -127,11 +127,11 @@ ask("질문 있으신가요?", () => alert('OK를 선택하셨습니다.'), resu
127127

128128
인수의 종류에 따라(위 예시에선 인수의 `length` 프로퍼티 값에 따라) 인수를 다르게 처리하는 방식을 프로그래밍 언어에선 [다형성(polymorphism)](https://en.wikipedia.org/wiki/Polymorphism_(computer_science)) 이라고 부릅니다. 자바스크립트 라이브러리를 뜯어보다 보면 다형성이 곳곳에서 사용되고 있다는 것을 확인할 수 있습니다.
129129

130-
## 사용자 지정 프로퍼티
130+
## 커스텀 프로퍼티
131131

132-
함수 객체에 자체적으로 만든 프로퍼티를 추가할 수도 있습니다.
132+
함수에 자체적으로 만든 프로퍼티를 추가할 수도 있습니다.
133133

134-
함수 호출 횟수를 `counter` 프로퍼티에 저장해봅시다.
134+
이런 특징을 이용해 함수 호출 횟수를 `counter` 프로퍼티에 저장해보겠습니다.
135135

136136
```js run
137137
function sayHi() {
@@ -142,7 +142,7 @@ function sayHi() {
142142
sayHi.counter++;
143143
*/!*
144144
}
145-
sayHi.counter = 0; // 초기값
145+
sayHi.counter = 0; // 초깃값
146146

147147
sayHi(); // Hi
148148
sayHi(); // Hi
@@ -153,10 +153,10 @@ alert( `호출 횟수: ${sayHi.counter}회` ); // 호출 횟수: 2회
153153
```warn header="프로퍼티는 변수가 아닙니다."
154154
`sayHi.counter = 0`와 같이 함수에 프로퍼티를 할당해도 함수 내에 지역변수 `counter`가 만들어지지 않습니다. `counter` 프로퍼티와 변수 `let counter`는 전혀 관계가 없습니다.
155155
156-
함수를 객체처럼 다룰 수 있고, 객체에 프로퍼티를 저장할 수 있지만, 이는 실행에 아무 영향을 끼치지 않습니다. 변수는 함수 프로퍼티가 아니고 함수 프로퍼티는 변수가 아니기 때문이죠. 둘 사이에는 공통점이 없습니다.
156+
프로퍼티를 저장하는 것처럼 함수를 객체처럼 다룰 수 있지만, 이는 실행에 아무 영향을 끼치지 않습니다. 변수는 함수 프로퍼티가 아니고 함수 프로퍼티는 변수가 아니기 때문입니다. 둘 사이에는 공통점이 없습니다.
157157
```
158158

159-
클로저를 함수 프로퍼티로 바꿔서 사용할 수도 있습니다. <info:closure> 챕터에서 살펴본 바 있는 counter 함수를 함수 프로퍼티를 사용해 바꿔보도록 하겠습니다.
159+
클로저는 함수 프로퍼티로 대체할 수 있습니다. <info:closure> 챕터에서 살펴본 바 있는 counter 함수를 함수 프로퍼티를 사용해 바꿔보도록 하겠습니다.
160160

161161
```js run
162162
function makeCounter() {
@@ -177,11 +177,11 @@ alert( counter() ); // 0
177177
alert( counter() ); // 1
178178
```
179179

180-
`count` 외부 렉시컬 환경이 아닌 함수 프로퍼티에 바로 저장하였습니다.
180+
이제 `count` 외부 렉시컬 환경이 아닌 함수 프로퍼티에 바로 저장됩니다.
181181

182-
이렇게 함수 프로퍼티에 정보를 저장하는 게 클로저를 사용하는 것보다 나은 방법일까요?
182+
그런데 과연 이렇게 함수 프로퍼티에 정보를 저장하는 게 클로저를 사용하는 것보다 나은 방법일까요?
183183

184-
두 방법의 차이점은 `count` 값이 외부변수에 저장되어있는 경우 드러납니다. 클로저를 사용한 경우는 외부 코드에서 `count`를 수정할없고, 오로지 중첩함수 내에서만 값을 수정할 수 있습니다. 함수 프로퍼티를 사용한 경우는 아래와 같이 외부에서 값을 수정할 수 있습니다.
184+
두 방법의 차이점은 `count` 값이 외부 변수에 저장되어있는 경우 드러납니다. 클로저를 사용한 경우엔 외부 코드에서 `count`에 접근할없습니다. 오직 중첩함수 내에서만 `count` 값을 수정할 수 있습니다. 반면 함수 프로퍼티를 사용해 `count`를 함수에 바인딩시킨 경우엔 다음 예시와 같이 외부에서 값을 수정할 수 있습니다.
185185

186186
```js run
187187
function makeCounter() {
@@ -203,7 +203,7 @@ alert( counter() ); // 10
203203
*/!*
204204
```
205205

206-
어떤 방법을 선택할지는 목적에 따라 달라지겠죠.
206+
따라서 구현 방법은 목적에 따라 선택하면 될 것 같습니다.
207207

208208
## 기명 함수 표현식
209209

@@ -227,9 +227,9 @@ let sayHi = function *!*func*/!*(who) {
227227

228228
이렇게 이름을 붙인다고 해서 뭐가 달라지는 걸까요? `"func"`이라는 이름은 어떤 경우에 붙이는 걸까요?
229229

230-
먼저 이렇게 이름을 붙여도 위 함수는 여전히 함수 표현식이라는 점에 주목해야 합니다. `"func"`이라는 이름을 `function` 다음에 붙이더라도 여전히 표현식을 할당한 형태를 유지하고, 함수 선언문으로 바뀌지 않습니다.
230+
먼저 이렇게 이름을 붙여도 위 함수는 여전히 함수 표현식이라는 점에 주목해야 합니다. `function` 뒤에 `"func"`이라는 이름을 붙이더라도 여전히 표현식을 할당한 형태를 유지하기 때문에 함수 선언문으로 바뀌지 않습니다.
231231

232-
이름을 추가한다고 해서 무언가 바뀌지 않죠.
232+
이름을 추가한다고 해서 기존에 동작하던 기능이 동작하지 않는 일은 발생하지 않습니다.
233233

234234
`sayHi()`로 호출하는 것도 여전히 가능합니다.
235235

@@ -241,12 +241,12 @@ let sayHi = function *!*func*/!*(who) {
241241
sayHi("John"); // Hello, John
242242
```
243243

244-
`func`같이 이름을 붙이면 아래와 같이 두 가지가 달라집니다.
244+
대신 `func`과 같은 이름을 붙이면 두 가지가 변화가 생깁니다. 이 두 변화 때문에 기명 함수 표현식을 사용하는 것이죠.
245245

246-
1. 이름을 사용해 함수 표현식 내부에서 자신을 참조할 수 있습니다.
247-
2. 함수 표현식 외부에선 이름을 사용할 수 없습니다.
246+
1. 이름을 사용해 함수 표현식 내부에서 자기 자신을 참조할 수 있습니다.
247+
2. 기명 함수 표현식 외부에선 이름을 사용할 수 없습니다.
248248

249-
아래 함수 `sayHi``who`에 값이 없는 경우, 인수로 `"Guest"`받습니다.
249+
함수 `sayHi`를 예시로 이에 대해 살펴봅시다. 함수 `sayHi``who`에 값이 없는 경우, 인수 `"Guest"`받고 자기 자신을 호출합니다.
250250

251251
```js run
252252
let sayHi = function *!*func*/!*(who) {
@@ -261,11 +261,11 @@ let sayHi = function *!*func*/!*(who) {
261261

262262
sayHi(); // Hello, Guest
263263

264-
// 아래와 같이 func를 호출하는 건 불가능합니다.
265-
func(); // Error, func is not defined (함수 표현식 밖에서는 func을 사용할 수 없습니다.)
264+
// 하지만 아래와 같이 func를 호출하는 건 불가능합니다.
265+
func(); // Error, func is not defined (기명 함수 표현식 밖에서는 그 이름에 접근할 수 없습니다.)
266266
```
267267

268-
`func`과 같은 이름을 붙여 사용하는 걸까요? 중첩 호출을 사용해도 될 것 같은데 말이죠.
268+
그런데 여기서 왜 중첩 호출을 할 때 `sayHi`대신 `func`을 사용했을까요?
269269

270270

271271
사실 대부분의 개발자는 아래와 같이 코드를 작성하곤 합니다.
@@ -282,26 +282,26 @@ let sayHi = function(who) {
282282
};
283283
```
284284

285-
이렇게 코드를 작성하면 외부 코드에 의해 `sayHi`가 변경될 경우 문제가 생깁니다. 함수 표현식을 새로운 변수에 할당하고, 기존 변수에 `null`을 할당하면 에러가 발생하죠.
285+
하지만 이렇게 코드를 작성하면 외부 코드에 의해 `sayHi`가 변경될 수 있다는 문제가 생깁니다. 함수 표현식을 새로운 변수에 할당하고, 기존 변수에 `null`을 할당하면 에러가 발생하죠.
286286

287287
```js run
288288
let sayHi = function(who) {
289289
if (who) {
290290
alert(`Hello, ${who}`);
291291
} else {
292292
*!*
293-
sayHi("Guest"); // Error: sayHi is not a function
293+
sayHi("Guest"); // TypeError: sayHi is not a function
294294
*/!*
295295
}
296296
};
297297

298298
let welcome = sayHi;
299299
sayHi = null;
300300

301-
welcome(); // sayHi는 더 이상 호출할 수 없습니다!
301+
welcome(); // 중첩 sayHi 호출은 더 이상 불가능합니다!
302302
```
303303

304-
에러의 원인은 함수가 `sayHi`를 외부 렉시컬 환경에서 가지고 오기 때문입니다. 지역 렉시컬 환경엔 `sayHi`가 없기 때문에 외부 렉시컬 환경에서 `sayHi`찾기 때문이죠. 함수 호출 시점에 외부 렉시컬 환경의 `sayHi``null`이 저장되어있기 때문에 에러가 발생합니다.
304+
에러는 함수가 `sayHi`자신의 외부 렉시컬 환경에서 가지고 오기 때문에 발생합니다. 지역(local) 렉시컬 환경엔 `sayHi`가 없기 때문에 외부 렉시컬 환경에서 `sayHi`찾는데, 함수 호출 시점에 외부 렉시컬 환경의 `sayHi``null`이 저장되어있기 때문에 에러가 발생합니다.
305305

306306
함수 표현식에 이름을 붙여주면 바로 이런 문제를 해결할 수 있습니다.
307307

@@ -324,30 +324,30 @@ sayHi = null;
324324
welcome(); // Hello, Guest (중첩 호출이 제대로 동작함)
325325
```
326326

327-
`"func"`함수 내부에서 찾을 수 있기 때문에 의도한 대로 예시가 동작합니다. 함수 외부에선 `"func"`을 사용할 수 없고, `"func"`외부 렉시컬 환경에서 가져오지도 않습니다. 함수 표현식에 붙인 이름은 현재 함수만 참조하도록 명세서에 정의되어있기 때문입니다.
327+
`"func"`이라는 이름은 함수 지역 수준(function-local)에 존재하므로 외부 렉시컬 환경에서 찾지 않아도 됩니다. 외부 렉시컬 환경에선 보이지도 않죠. 함수 표현식에 붙인 이름은 현재 함수만 참조하도록 명세서에 정의되어있기 때문입니다.
328328

329-
이렇게 기명 함수 표현식을 이용하면 `sayHi``welcome` 같은 외부 변수의 변경과 관계없이 `func`이라는 '내부 함수 이름'을 사용해 언제든 함수 표현식이 자기 자신을 호출할 수 있게 만들 수 있습니다.
329+
이렇게 기명 함수 표현식을 이용하면 `sayHi``welcome` 같은 외부 변수의 변경과 관계없이 `func`이라는 '내부 함수 이름'을 사용해 언제든 함수 표현식 내부에서 자기 자신을 호출할 수 있습니다.
330330

331331
```smart header="함수 선언문엔 내부 이름을 지정할 수 없습니다."
332-
'내부 이름'은 함수 표현식에만 사용할 수 있고, 함수 선언문엔 사용할 수 없습니다. 함수 선언문을 통해 만든 함수엔 '내부' 이름을 지정할 수 있는 문법이 없습니다.
332+
지금까지 살펴본 '내부 이름'은 함수 표현식에만 사용할 수 있고, 함수 선언문엔 사용할 수 없습니다. 함수 선언문엔 '내부' 이름을 지정할 수 있는 문법이 없습니다.
333333
334-
내부 이름이 필요하다면 함수 선언문 대신 함수 표현식을 사용해 함수를 다시 정의하면 됩니다.
334+
개발을 하다 보면 믿을만한 내부 이름이 필요할 때가 생기곤 합니다. 이 때 바로 함수 선언문을 기명 함수 표현식으로 다시 정의하면 됩니다.
335335
```
336336

337337
## 요약
338338

339339
함수는 객체입니다.
340340

341-
다음 함수 객체 프로퍼티는 여러 곳에서 사용할 수 있습니다.
341+
이번 챕터에선 객체로서의 함수에서 사용 할 수 있는 프로퍼티 두 가지를 다뤄보았습니다.
342342

343-
- `name` -- 함수의 이름이 저장됩니다. 함수 선언부에서 이름을 가져오는데, 익명 함수인 경우는 자바스크립트 엔진이 컨텍스트(할당 등)를 이용해 이름을 추론합니다.
344-
- `length` -- 함수 선언부에 있는 인수의 수로 나머지 매개변수는 포함하지 않습니다.
343+
- `name` -- 함수의 이름이 저장됩니다. 대개는 함수 선언부에서 이름을 가져오는데, 선언부에 이름이 없는 경우엔 자바스크립트 엔진이 컨텍스트(할당 등)를 이용해 이름을 추론합니다.
344+
- `length` -- 함수 선언부에 있는 인수의 수로 나머지 매개변수는 포함되지 않습니다.
345345

346346
함수 표현식으로 함수를 정의하였는데 이름이 있다면 이를 기명 함수 표현식이라 부릅니다. 기명 함수 표현식의 이름은 재귀 호출과 같이 함수 내부에서 자기 자신을 호출하고자 할 때 사용할 수 있습니다.
347347

348-
함수 객체엔 다양한 프로퍼티를 추가할 수 있는데, 잘 알려진 자바스크립트 라이브러리를 뜯어보면 이런 커스텀 프로퍼티에 대한 예시들을 많이 찾아볼 수 있습니다.
348+
함수엔 다양한 프로퍼티를 추가할 수 있습니다. 널리 쓰이는 자바스크립트 라이브러리 상당수에서 이런 커스텀 프로퍼티를 잘 활용하고 있습니다.
349349

350-
이런 라이브러리들은 '주요' 함수 하나를 만들고 여기에 다양한 '헬퍼' 함수를 붙이는 식으로 구성되어있습니다. [jQuery](https://jquery.com)주요 함수 `$`를 중심으로 구성되어있죠. [lodash](https://lodash.com)는 주요 함수 `_``_.clone`, `_.keyBy`등의 프로퍼티를 추가하는 식으로 구성되어있습니다. 자세한 정보는 lodash [공식 문서](https://lodash.com/docs)에서 찾아볼 수 있습니다. 이렇게 함수 하나에 다양한 헬퍼 함수를 붙여 라이브러리를 만들면 라이브러리 하나가 전역 변수 하나만 차지하므로 전역 공간을 더럽히지 않는다는 장점이 있습니다. 이름 충돌도 방지할 수 있죠.
350+
이런 라이브러리들은 '주요' 함수 하나를 만들고 여기에 다양한 '헬퍼' 함수를 붙이는 식으로 구성됩니다. [jQuery](https://jquery.com)이름이 `$`인 주요 함수로 이루어져 있습니다. [lodash](https://lodash.com)는 주요 함수 `_``_.clone`, `_.keyBy`등의 프로퍼티를 추가하는 식으로 구성되죠. 자세한 정보는 lodash [공식 문서](https://lodash.com/docs)에서 찾아볼 수 있습니다. 이렇게 함수 하나에 다양한 헬퍼 함수를 붙여 라이브러리를 만들면 라이브러리 하나가 전역 변수 하나만 사용하므로 전역 공간을 더럽히지 않는다는 장점이 있습니다. 이름 충돌도 방지할 수 있죠.
351351

352352

353-
라이브러리에서 정의한 메인 함수와 여기에 딸린 프로퍼티에 정의된 다양한 기능을 사용하면 다양한 작업을 수행할 수 있습니다.
353+
이렇게 객체로서의 함수 특징을 이용해 커스텀 프로퍼티를 만들면 함수는 자기 자신을 이용해 원하는 일을 수행할 수 있고, 함수 자기 자신에 딸린 프로퍼티의 기능도 사용할 수 있다는 장점이 있습니다.

0 commit comments

Comments
 (0)