Skip to content

Commit 56d9a05

Browse files
committed
Create chapter_18.md
1 parent 5f910d8 commit 56d9a05

1 file changed

Lines changed: 319 additions & 0 deletions

File tree

book/이용우/chapter_18.md

Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
# Chapter 18 - 함수와 일급 객체
2+
아래의 조건을 만족하는 객체를 일급 객체라고 합니다.
3+
- 무명의 리터럴로 생성이 가능하다. (= 런타임에 생성이 가능하다)
4+
- 코드 내에서 특정 값을 바로 생성하거나 정의할 수 있는 방식
5+
- 변수나 자료구조(객체, 배열 등)에 저장할 수 있다.
6+
- 함수의 매개변수에 전달할 수 있다. (= 매개변수로 함수를 받을 수 있다)
7+
- 함수의 반환값으로 사용할 수 있다. (= 리턴값으로 함수를 리턴할 수 있다)
8+
9+
<br>
10+
11+
자바스크립트의 함수는 위 조건을 모두 만족하므로 일급 객체입니다.
12+
13+
14+
``` js
15+
// 1. 함수는 무명의 리터럴로 생성 가능하다.
16+
// 2. 함수는 변수에 저장할 수 있다.
17+
const increase = function (num) {
18+
return ++num;
19+
};
20+
const decrease = function (num) {
21+
return --num;
22+
};
23+
24+
// 2. 함수는 객체에 저장할 수 있다.
25+
const auxs = function (num) {
26+
return --num;
27+
};
28+
29+
// 3. 함수의 매개변수에 전달할 수 있다.
30+
// 4. 함수의 반환값으로 사용할 수 있다.
31+
function makeCounter(aux) {
32+
let num = 0;
33+
return function () {
34+
num = awx(num);
35+
return num;
36+
};
37+
}
38+
39+
// 3. 함수는 매개변수에게 함수를 전달할 수 있다.
40+
const increase = makeCounter(auxs.increase);
41+
console.log(increaser()); // 1
42+
console.log(increaser()); // 2
43+
```
44+
45+
46+
<br>
47+
48+
일급 객체로서 함수가 가지는 가장 큰 특징은
49+
일반 객체와 같이 함수의 매개변수에 전달할 수 있으며, 함수의 반환값으로도 사용할 수 있다는 것입니다.
50+
이는 함수형 프로그래밍을 가능하게 하는 자바스크립트의 장점 중 하나입니다.
51+
52+
<br><br>
53+
54+
### 함수 객체의 프로퍼티
55+
함수는 객체입니다. 따라서 함수도 프로퍼티를 가질 수 있습니다.
56+
57+
``` js
58+
function square(number) {
59+
return number * number;
60+
}
61+
62+
console.dir(square);
63+
```
64+
<img src="https://github.com/user-attachments/assets/5310582d-f0b8-4dfa-8815-aaa4cc31cb70" width=350>
65+
66+
67+
<br>
68+
69+
`square` 함수의 모든 프로퍼티에 대해
70+
프로퍼티 어트리뷰트를 `Object.getOwnPropertyDescriptors` 메소드로 확인해보면 다음과 같습니다.
71+
72+
``` js
73+
Object.getOwnPropertyDescriptors(square);
74+
```
75+
76+
<img src="https://github.com/user-attachments/assets/9f3e6d8d-3688-4056-8c35-cc56af9fd00b" width=500>
77+
78+
<br>
79+
80+
``` js
81+
// __proto__는 square 함수의 프로퍼티가 아니다.
82+
Object.getOwnPropertyDescriptor(square, '__proto__'); // undefined
83+
84+
// __proto__는 Object.prototype 객체의 접근자 프로퍼티이다.
85+
// square 함수는 Object.prototype 객체로부터 __proto__ 접근자 프로퍼티를 상속받는다.
86+
Object.getOwnPropertyDescriptor(Object.prototype, '__proto__');
87+
// {enumerable: false, configurable: true, get: ƒ, set: ƒ}
88+
```
89+
90+
<br>
91+
92+
이와 같이 `arguments`, `caller`, `length`, `name`, `prototype` 프로퍼티는 모두 함수 객체의 데이터 프로퍼티이다. <font color='orange'>이 프로퍼티들은 일반 객체에는 없는 함수 객체 고유의 프로퍼티입니다.</font>
93+
94+
다만, `__proto__`는 접근자 프로퍼티이며, 함수 객체 고유의 프로퍼티가 아니라 `Object.prototype` 객체의 프로퍼티를 상속받은 것을 알 수 있습니다.
95+
96+
`Object.prototype` 객체의 프로퍼티는 모든 객체가 상속받아 사용할 수 있습니다.
97+
즉, `Object.prototype` 객체의 `__proto__` 접근자 프로퍼티는 모든 객체가 사용할 수 있습니다.
98+
> 상속은 19장 "프로토타입"에서 자세히 다룰 것이다.
99+
100+
101+
<br><br>
102+
103+
#### arguments 프로퍼티
104+
함수 객체의 `arguments` 프로퍼티 값은 `arguments` 객체입니다.
105+
`arguments` 객체는 함수 호출 시 전달된 인수(`argument`)들의 정보를 가지고 있는 순회 가능한(`iterable`) 유사 배열 객체이며, 함수 내부에서 지역 변수처럼 사용됩니다.
106+
107+
자바스크립트는 함수의 매개변수와 인수의 개수가 일치하는지 확인하지 않습니다.
108+
따라서 함수 호출 시 매개변수 개수만큼 인수를 전달하지 않아도 에러가 발생하지 않습니다.
109+
110+
``` js
111+
function multiply(x, y) {
112+
console.log(arguments);
113+
return x * y;
114+
}
115+
116+
console.log(multiply()); // NaN
117+
console.log(multiply(1)); // NaN
118+
console.log(multiply(1, 2)); // 2
119+
console.log(multiply(1, 2, 3)); // 2
120+
121+
```
122+
123+
<br>
124+
125+
다만 초과된 인수가 그냥 버려지는 것은 아닙니다.
126+
모든 인수는 암묵적으로 `arguments` 객체의 프로퍼티로 보관됩니다.
127+
128+
<img src="https://github.com/user-attachments/assets/165a3e1e-0322-49f5-9f40-be9eb2ffe31c" width=400>
129+
130+
<br>
131+
132+
`arguments` 객체는 인수를 프로퍼티 값으로 소유하며 프로퍼티 키는 인수의 순서를 나타냅니다.
133+
`arguments` 객체의 `callee` 프로퍼티는 호출되어 함수 자기자신을 가리키고
134+
`arguments` 객체의 `length` 프로퍼티는 인수의 개수를 가리킵니다.
135+
136+
137+
<br>
138+
139+
※ arguments 객체의 Symbol(Symbol.iterator) 프로퍼티
140+
`arguments` 객체의 `Symbol(Symbol.iterator)` 프로퍼티는 `arguments` 객체를
141+
순회 가능한 자료구조인 이터러블(`iterable`)로 만들기 위한 프로퍼티입니다.
142+
143+
``` js
144+
function multiply(x, y) {d
145+
// itertor
146+
const iterator = arguments[Symbol.iterator]();
147+
148+
// iterator의 next() 메소드를 호출하여 이터러블 객체 `arguments`를 순회
149+
console.log(iterator.next()); // {value: 1, done: false}
150+
console.log(iterator.next()); // {value: 2, done: false}
151+
console.log(iterator.next()); // {value: 3, done: false}
152+
console.log(iterator.next()); // {value: undefined, done: true}
153+
154+
return x * y;
155+
}
156+
157+
multiply(1, 2, 3);
158+
```
159+
160+
<br>
161+
162+
`arguments` 객체는 매개변수 개수를 확정할 수 없는 가변 인자 함수를 구현할 때 특히 유용합니다.
163+
164+
``` js
165+
function sum() {
166+
let res = 0;
167+
168+
for (let i = 0; i < arguments.length; i++) {
169+
res += arguments[i];
170+
}
171+
return res;
172+
}
173+
174+
console.log(sum()); // 0
175+
console.log(sum(1, 2)); // 3
176+
console.log(sum(1, 2, 3)); // 6
177+
```
178+
179+
<br>
180+
181+
arguments 객체는 유사 배열 객체이기 때문에
182+
배열과 같이 사용하고 싶다면, `Function.prototype.call`, `Function.prototype.apply`와 같이 간접 호출해야 하는 번거로움이 있습니다.
183+
184+
``` js
185+
function sum(){
186+
// arguments 객체를 배열로 반환
187+
const array = Array.prototype.slice.call(arguments);
188+
return array.reduce(function (pre, cur) {
189+
return pre + cur;
190+
}, 0);
191+
}
192+
193+
console.log(sum(1, 2)); // 3
194+
console.log(sum(1, 2, 3, 4, 5)); // 15
195+
```
196+
197+
<br>
198+
199+
이런 번거로움을 해결하기 위해 ES6에서는 Rest 파라미터가 도입되었습니다.
200+
201+
``` js
202+
function sum( ...args) {
203+
return args.reduce((pre, cur) => pre + cur, 0);
204+
}
205+
206+
console.log(sum(1, 2));
207+
console.log(sum(1, 2, 3, 4, 5));
208+
```
209+
210+
<br><br>
211+
212+
#### caller 프로퍼티
213+
`caller` 프로퍼티는 ECMAScript 사양에 포함되지 않은 비표준 프로퍼티입니다.
214+
이후 표준화될 예정이 없는 프로퍼티이므로 사용하지 않고 참고만 하는 것을 추천합니다.
215+
216+
`caller` 프로퍼티는 함수 자신을 호출한 함수를 가리킵니다.
217+
218+
``` js
219+
function foo(func) {
220+
return func();
221+
}
222+
223+
function bar() {
224+
return 'caller : ' + bar.caller;
225+
}
226+
227+
console.log(foo(bar)); // caller : function foo(func) {...}
228+
console.log(bar()); // caller : null
229+
```
230+
231+
<br><br>
232+
233+
#### length 프로퍼티
234+
함수 객체의 `length` 프로퍼티는 함수를 정의할 때 선언한 매개변수의 개수를 가리킵니다.
235+
236+
``` js
237+
function foo() {}
238+
console.log(foo.length); // 0
239+
240+
function bar(x) {
241+
return x;
242+
}
243+
console.log(bar.length); // 1
244+
245+
function bar2(x, y) {
246+
return x * y;
247+
}
248+
console.log(bar2.length); // 2
249+
```
250+
251+
252+
<br><br>
253+
254+
#### name 프로퍼티
255+
<font color='orange'>함수 객체의 `name` 프로퍼티는 함수 이름을 나타냅니다.</font>
256+
`name` 프로퍼티는 ES5에서는 익명 함수의 경우 빈 문자열을 값으로 갖지만,
257+
ES6에서는 함수 객체를 가리키는 식별자를 값으로 갖습니다.
258+
259+
``` js
260+
// 가명 함수 표현식
261+
const namedFunc = function foo() ();
262+
console.log(namedFunc.name); // foo
263+
264+
// 익명 함수 표현식
265+
const anonymousFunc = function() {};
266+
console.log(anonymousFunc.name); // anonymousFunc
267+
268+
// 함수 선언문(Function declaration)
269+
function bar() {}
270+
console.log(bar.name); // bar
271+
```
272+
273+
274+
<br><br>
275+
276+
277+
#### __proto__ 접근자 프로퍼티
278+
모든 객체는 `[[Prototype]]` 이라는 내부 슬롯을 가집니다.
279+
`__proto__` 프로퍼티는 `[[Prototype]]` 내부 슬롯이 가리키는 프로토타입 객체에 접근하기 위해 사용하는 접근자 프로퍼티입니다.
280+
내부 슬롯에는 직접 접근할 수 없고 간접적인 접근 방식을 제공하는 경우에 한하여 접근할 수 있습니다.
281+
282+
``` js
283+
conse obj = { a: 1 };
284+
285+
// 객체 리터럴 방식으로 생성한 객체의 프로토토압 객체는 Object.prototype 이다.
286+
console.log(obj.__proto__ === Object.prototype); // true
287+
288+
// 객체 리터럴 방식으로 생성한 객체는 프로토타입 객체인 Object.prototype의 프로퍼티를 상속받는다.
289+
console.log(obj.hasOwnProperty('a')); // true
290+
console.log(obj.hasOwnProperty('__proto__')); // false
291+
```
292+
293+
294+
<br><br>
295+
296+
#### prototype 프로퍼티
297+
`prototype` 프로퍼티는 생성자 함수로 호출할 수 있는 함수 객체, 즉 `constructor`만이 소유하는 프로퍼티입니다.
298+
일반 객체와 생성자 함수로 호출할 수 없는 `non-constructor`에는 `prototype` 프로퍼티가 없습니다.
299+
300+
``` js
301+
// 함수 객체는 `prototype` 프로퍼티를 소유한다.
302+
(function() {}).hasOwnProperty('prototype'); // true
303+
304+
// 일반 객체는 `prototype` 프로퍼티를 소유하지 않는다.
305+
({}).hasOwnProperty('prototype'); // false
306+
```
307+
308+
<br>
309+
310+
`prototype` 프로퍼티는 함수가 객체를 생성하는 생성자 함수로 호출될 때,
311+
생성자 함수가 생성할 인스턴스의 프로토타입 객체를 생성합니다.
312+
313+
``` js
314+
function Person(name) {
315+
this.name = name;
316+
}
317+
318+
const person1 = new Person("Lee");
319+
```

0 commit comments

Comments
 (0)