|
| 1 | +# Chapter 18 - 함수와 일급 객체 |
| 2 | +## 1. 일급 객체 |
| 3 | +일급 객체란, 자바스크립트에서 다음 같은 조건을 만족하는 객체를 뜻한다. |
| 4 | +1. 무명의 리터럴로 생성할 수 있다. 즉, **런타임에 생성**이 가능하다. |
| 5 | +2. **변수나 자료구조**(객체, 배열 등)**에 저장**할 수 있다. |
| 6 | +3. 함수의 **매개변수에 전달**할 수 있다. |
| 7 | +4. 함수의 **반환값으로 사용**할 수 있다. |
| 8 | + |
| 9 | +**자바스크립트의 함수는** 위의 조건을 모두 만족하므로 **일급 객체**다.<br/> |
| 10 | +즉, 함수는 **값을 사용할 수 있는 곳**(변수 할당문, 객체의 프로퍼티 값, 배열의 요소, 함수 호출의 인수, 함수 반환문)이라면<br/> |
| 11 | +**어디서든지 리터럴로 정의**할 수 있으며, **런타임에 함수 객체로 평가**된다. |
| 12 | + |
| 13 | +이러한 자바스크립트 함수의 특징은, 함수형 프로그래밍을 가능케 하며 자바스크립트의 장점 중 하나다. |
| 14 | + |
| 15 | + |
| 16 | +## 2. 함수 객체의 프로퍼티 |
| 17 | +함수는 객체다. 따라서 함수도 프로퍼티를 가진다.<br/> |
| 18 | +함수 객체의 프로퍼티를 하나씩 살펴보자. |
| 19 | + |
| 20 | +### 2-1. `arguments` 프로퍼티 |
| 21 | +함수 객체의 `arguments` 프로퍼티 값은, `arguments` 객체다.<br/> |
| 22 | +**`arguments` 객체**는 함수 호출 시 전달된 **인수(arguments)들의 정보**를 담은, **순회 가능한(iterable) 유사 배열 객체**이며,<br/> |
| 23 | +함수 내부에서 지역변수처럼 사용한다. 즉, **함수 외부에서는 참조할 수 없다**. |
| 24 | + |
| 25 | + |
| 26 | + |
| 27 | +위 콘솔 사진에서 빨간 네모 표시된 부분이 인수의 정보가 보여지는 부분이다.<br/> |
| 28 | +`arguments` 객체는 다음과 같이 매개변수 개수를 확정할 수 없는, **가변 인자 함수를 구현할 때 유용**하다. |
| 29 | + |
| 30 | +```javascript |
| 31 | +function sum() { |
| 32 | + let res = 0; |
| 33 | + |
| 34 | + // arguments 객체는 length 프로퍼티가 있는 유사 배열 객체이므로, for문으로 순회할 수 있다. |
| 35 | + for (let i = 0; i < arguments.length; i++) { |
| 36 | + res += arguments[i]; |
| 37 | + } |
| 38 | + |
| 39 | + return res; |
| 40 | +} |
| 41 | + |
| 42 | +console.log(sum()) // 0 |
| 43 | +console.log(sum(1, 2)) // 3 |
| 44 | +console.log(sum(1, 2, 3)) // 6 |
| 45 | +``` |
| 46 | + |
| 47 | +`arguments` 객체는 앞서 말했듯 실제 배열이 아닌, **array-like object(유사 배열 객체)이다**.<br/> |
| 48 | +유사 배열 객체란, length 프로퍼티를 지니며 for문으로 순회할 수 있는 객체를 말한다.<br/> |
| 49 | +(이터러블이 도입된 ES6부터 `arguments` 객체는 유사 배열 객체이면서 **이터러블**(이후 34장 '이터러블' 참고)이기도 하다.) |
| 50 | + |
| 51 | +### 2-2. `caller` 프로퍼티 |
| 52 | +`caller` 프로퍼티는 ECMAScript 사양에 포함하지 않는 비표준 프로퍼티이므로 생략한다. |
| 53 | + |
| 54 | +### 2-3. `length` 프로퍼티 |
| 55 | +함수 객체의 `length` 프로퍼티는 다음 예제와 같이 **함수를 정의할 때 선언한 매개변수의 개수**를 가리킨다. |
| 56 | +```javascript |
| 57 | +function foo() {} |
| 58 | +console.log(foo.length); // 0 |
| 59 | + |
| 60 | +function bar(x) { |
| 61 | + return x; |
| 62 | +} |
| 63 | +console.log(foo.length); // 1 |
| 64 | + |
| 65 | +function baz(x, y) { |
| 66 | + return x * y |
| 67 | +} |
| 68 | +console.log(foo.length); // 2 |
| 69 | +``` |
| 70 | +**`arguments` 객체**의 `length` 프로퍼티와, **함수 객체**의 `length` 프로퍼티는 다른 개념인 걸 반드시 숙지하자.<br/> |
| 71 | +전자는 **arguments(인자)의 개수**를 가리키고, 후자는 **parameters(매개변수)의 개수**를 가리킨다. |
| 72 | + |
| 73 | +### 2-4. `name` 프로퍼티 |
| 74 | +함수 객체의 `name` 프로퍼티는 아래 예제처럼 **함수 이름을 나타낸다**. ES6부터 정식 표준이 되었다.<br/> |
| 75 | +주의해야 할 점은, `name` 프로퍼티는 **ES5와 ES6에서 동작을 달리한다**는 점이다.<br/> |
| 76 | +ES5에서는 익명 함수 표현식의 `name` 프로퍼티의 값이 **빈 문자열**이고, ES6에서는 함수 객체를 가리키는 **식별자**다. |
| 77 | + |
| 78 | +```javascript |
| 79 | +// 기명 함수 표현식 |
| 80 | +var namedFunc = function foo() {}; |
| 81 | +console.log(namedFunc.name); // foo |
| 82 | + |
| 83 | +// 익명 함수 표현식 |
| 84 | +var anonymousFunc = function() {}; |
| 85 | +// ES5: name 프로퍼티의 값이 빈 문자열이다. |
| 86 | +// ES6: name 프로퍼티의 값이 함수 객체를 가리키는 식별자다. |
| 87 | +console.log(anonymousFunc.name); // anonymousFunc |
| 88 | + |
| 89 | +// 함수 선언문 |
| 90 | +function bar() {}; |
| 91 | +console.log(bar.name); // bar |
| 92 | +``` |
| 93 | + |
| 94 | +### 2-5. `__proto__` 접근자 프로퍼티 |
| 95 | +모든 객체는 [[Prototype]]이라는 내부 슬롯을 갖는다. [[Prototype]]은 프로토타입 객체를 가리킨다. (프로토타입에 관한 자세한 내용은 19장 '프로토타입' 참고)<br/> |
| 96 | +`__proto__`는 [[Prototype]] 내부 슬롯이 가리키는 프로토타입 객체에 접근하고자 사용하는 **접근자 프로퍼티**다. |
| 97 | + |
| 98 | +[[Prototype]] 내부 슬롯에는 직접 접근할 수 없고, `__proto__` 접근자 프로퍼티를 통해 **간접적으로** 프로토타입 객체에 접근할 수 있다. |
| 99 | + |
| 100 | +### 2-6. `prototype` 프로퍼티 |
| 101 | +`prototype` 프로퍼티는 **생성자 함수가 생성할 인스턴스의 프로토타입 객체**를 가리킨다. |
| 102 | + |
| 103 | +`prototype` 프로퍼티는 **constructor만이 소유하는** 특별한 프로퍼티다.<br/> |
| 104 | +따라서 일반 객체와 생성자 함수로 호출할 수 없는 non-constructor에는 `prototype` 프로퍼티가 없다. |
| 105 | +```javascript |
| 106 | +// 함수 객체는 prototype 프로퍼티를 갖는다. |
| 107 | +(function () {}).hasOwnProperty('prototype'); // true |
| 108 | + |
| 109 | +// 일반 객체는 prototype 프로퍼티를 갖지 않는다. |
| 110 | +({}).hasOwnProperty('prototype'); // false |
| 111 | +``` |
| 112 | + |
| 113 | +끝. |
0 commit comments