18장 함수와 일급 객체


일급객체의 조건

  1. 무명의 리터럴로 생성할 수 있다. 런타임에 생성 가능
  2. 변수나 자료구조(객체,배열 등)에 저장할 수 있다.
  3. 함수의 매개변수에 전달할 수 있다.
  4. 함수의 반환값으로 사용할 수 있다.
// 1. 함수는 무명의 리터럴로 생성할 수 있다.
// 2. 함수는 변수에 저장할 수 있다.
// 런타임(할당 단계)에 함수 리터럴이 평가되어 함수 객체가 생성되고 변수에 할당된다.
const increase = function (num) {
  return ++num;
};

const decrease = function (num) {
  return --num;
};

// 2. 함수는 객체에 저장할 수 있다.
const auxs = { increase, decrease };

// 3. 함수의 매개변수에게 전달할 수 있다.
// 4. 함수의 반환값으로 사용할 수 있다.
function makeCounter(aux) {
  let num = 0;

  return function () {
    num = aux(num);
    return num;
  };
}

// 3. 함수는 매개변수에게 함수를 전달할 수 있다.
const increaser = makeCounter(auxs.increase);
console.log(increaser()); // 1
console.log(increaser()); // 2

// 3. 함수는 매개변수에게 함수를 전달할 수 있다.
const decreaser = makeCounter(auxs.decrease);
console.log(decreaser()); // -1
console.log(decreaser()); // -2

함수는 값과 동일하게 취급할 수 있다.
일반 객체와 달리 호출할 수 있고, 고유의 프로퍼티를 가지는 건 앞에서 나왔다.

함수 객체의 프로퍼티

function square(number) {
  return number * number;
}

console.log(Object.getOwnPropertyDescriptors(square));
/*
{
  length: {value: 1, writable: false, enumerable: false, configurable: true},
  name: {value: "square", writable: false, enumerable: false, configurable: true},
  arguments: {value: null, writable: false, enumerable: false, configurable: false},
  caller: {value: null, writable: false, enumerable: false, configurable: false},
  prototype: {value: {...}, writable: true, enumerable: false, configurable: false}
}
*/

// __proto__는 square 함수의 프로퍼티가 아니다.
console.log(Object.getOwnPropertyDescriptor(square, '__proto__')); // undefined

// __proto__는 Object.prototype 객체의 접근자 프로퍼티다.
// square 함수는 Object.prototype 객체로부터 __proto__ 접근자 프로퍼티를 상속받는다.
console.log(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__'));
// {get: ƒ, set: ƒ, enumerable: false, configurable: true}

argument, caller, length, name, prototype 은 함수 객체 고유의 데이터 프로퍼티이다.
__proto__접근자 프로퍼티이고, 고유의 프로퍼티가 아니라, Object.prototype 객체의 프로퍼티를 상속받았다. 즉, 모든 객체들이 사용할 수 있는 접근자 프로퍼티.

arguments 프로퍼티

arguments 프로퍼티 값은 arguments 객체이다.
argument 객체는 함수 호출시 전달된 인수들의 정보를 담고 있는 순회 가능한 유사 배열 객체. 함수 내부에서 지역 변수 처럼 사용됨. 즉, 외부에서는 참조할 수 없음.

모든 인수는 암묵적으로 argument 객체의 프로퍼티로 보관됨.

Untitled 19.png|Untitled 19.png

key 값은 인수의 순서. callee 프로퍼티는 호출되어 arguments 객체를 생성한 함수, 즉 함수 자신을 가리키고. length 는 인수 갯수 가르킴.

argument 객체는 가변 인자 함수 구현할 때 유용
argument 객체는 유사배열 객체이면서 이터러블이라고 한다. (자세한 건 34장 이터러블)
⇒ 배열 메서드 사용못하고 간접 호출해야한다고 함.

function sum() {
  // arguments 객체를 배열로 변환
  const array = Array.prototype.slice.call(arguments);
  return array.reduce(function (pre, cur) {
    return pre + cur;
  }, 0);
}

console.log(sum(1, 2));          // 3
console.log(sum(1, 2, 3, 4, 5)); // 15

번거로워서 Rest 파라미터라는게 es6 부터 도입됐다고 한다.

// ES6 Rest parameter
function sum(...args) {
  return args.reduce((pre, cur) => pre + cur, 0);
}

console.log(sum(1, 2));          // 3
console.log(sum(1, 2, 3, 4, 5)); // 15

calller 프로퍼티(별로 안중요)

함수 자신을 호출한 함수를 가르킨다.

function foo(func) {
  return func();
}

function bar() {
  return 'caller : ' + bar.caller;
}

// 브라우저에서의 실행한 결과
console.log(foo(bar)); // caller : function foo(func) {...}
console.log(bar());    // caller : null

첫번째 경우 bar을 foo 함수 내에서 호출해서 foo가 반환된 모습

length 프로퍼티

함수 객체에서 : 매개변수 개수
argument 객체에서 : 인자 개수

name 프로퍼티

함수 이름을 가르킨다.
무기명 함수의 경우 함수 객체를 가르키는 변수 이름을 값으로 가짐.

__proto__ 접근자 프로퍼티

모든 객체는 [[Prototype]] 이라는 내부 슬롯 가짐.
__proto__ 이용해서 간접 접근 가능.

prototype 프로퍼티

prototype 프로퍼티는 생성자 함수로 호출할 수 있는 함수 객체, constructor 만이 소유하는 프로퍼티

// 함수 객체는 prototype 프로퍼티를 소유한다.
(function () {}).hasOwnProperty('prototype'); // -> true

// 일반 객체는 prototype 프로퍼티를 소유하지 않는다.
({}).hasOwnProperty('prototype'); // -> false

생성자 함수로 호출될 때 생성자 함수가 생성할 인스턴스의 프로터타입 객체를 가리킴

hasOwnProperty 메서드는 인수로 전달받은 프로퍼티 키가 객체 고유의 프로퍼티 키인 경우에만 true, 상속받으면 false 반환함.

reference