Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

nhyunzi

[모던 자바스크립트 Deep Dive] 18 함수와 일급 객체 본문

카테고리 없음

[모던 자바스크립트 Deep Dive] 18 함수와 일급 객체

nhyunzi 2024. 12. 16. 08:04

18.1 일급 객체

무명의 리터럴로 생성할 수 있다. 런타임에 생성 가능하다. 변수나 자료구조(객체, 배열 등)에 저장할 수 있다. 함수의 매개변수에 전달할 수 있다. 함수의 반환값으로 사용할 수 있다.

함수는 위의 조건을 모두 만족하기 때문에 일급 객체다.

//1. 무명의 리터럴로 생성
//2. 변수에 저장할 수 있다.
const increase = function(num){
  return ++num;
};
const decrease = function(num){
  return --num;
};
 
//2. 객체에 저장할 수 있다. 
const predicates = { increase, decrease };
 
//3. 함수의 매개변수에 전달할 수 있다.
//4. 함수의 반환값으로 사용할 수 있다.
function makeCounter(predicate){
  let num = 0;
  
  return function(){
    num = predicate(num);
    return num;
  }
}
 
//3. 함수의 매개변수에 전달할 수 있다.
const increaser = makeCounter(predicates.increase);
const increaser = makeCounter(predicates.decrease);


결국 함수가 일급 객체라는 것은 함수를 객체와 동일하게 사용할 수 있다는 의미이다. 함수는 값을 사용할수 있는 곳이라면 어디서든 리터럴로 정의할 수 있으며 런타임에 함수 객체로 평가된다. 일반 객체와는 큰 차이가 있는데 일반 객체는 호출할 수 없고 함수 객체는 호출할 수 있으며 일반 객체에는 없는 고유 프로퍼티를 소유하고있다.

18.2 함수 객체의 프로퍼티


함수도 객체이다. Object.getOwnPropertyDescription 메서드로 확인해 나오는 프로퍼티를 살펴볼 수 있다.
[length, name, arguments, caller, prototype]

arguments 프로퍼티
함수 객체의 arguments 프로퍼티 값는 arguments 객체이다. 함수 호출 시 전달된 인수들의 정보를 담고 있는 순회 가능한 유사 배열 객체이며, 함수 내부에서 지역 변수처럼 사용된다ES3부터 Function.arguments와 같은 사용법은 권장하지 않으며 함수 내부에서 지역 변수처럼 사용할 수 있는 arguments 객체를 참조하도록 한다.

함수를 정의할 때 선언한 매개변수는 함수 몸체 내부에서 변수와 동일하게 취급된다. 즉, 함수 몸체 내에서 암묵적으로 매개변수가 선언되고 undefined로 초기화 되고 인수가 할당되기 때문에 매개변수 개수 만큼 인수를 전달하지 않아도 에러가 발생하지 않는다.

초과된 인수는 그냥 버려지는것은 아니고 모든 인수가 암묵적으로 보관되는 arguments 객체의 프로퍼티에 보관된다.

arguments 객체는 인수를 프로퍼티 값으로 소유하며 프로퍼티 키는 인수의 순서를 나타낸다.
argumetns 객체의 callee 프로퍼티는 호출되어 arguments 객체를 생성한 함수, 즉 자신을 가리킨다. arguments 객체의 length는 인수의 개수를 가리킨다.  
Symbol(Symbol.iterator) 프로퍼티는 arguments 객체를 순회 가능한 자료구조인 이터러블로 만들기 위한 프로퍼티이다.

function multiply(x,y){
  const iterator = arguments[Symbol.iterator]();
  console.log(iterator.next()); //{value: 1, done: false}
  console.log(iterator.next()); //{value: 2, done: false}
  console.log(iterator.next()); //{value: 3, done: false}
  console.log(iterator.next()); //{value: undefined, done: true}
  return x*y;
}
multiply(1,2,3);


arguments 객체는 매개변수 개수를 확정할 수 없는 가변 인자 함수를 구현할 때 유용하다.
하지만 주의해야할 점은 arguments 객체는 배열 형태로 인자 정보를 담고있지만 실제 배열이 아닌 유사 배열 객체로 length 프로퍼티를 가지며 for문으로 순회할 수 있는 객체이다. 유사 배열 객체는 배열이 아니기 때문에 배열 메서드를 사용할 경우 에러가 발생한다.배열 메서드를 사용하기 위해선 Function.prototype.call, Function.prototype.apply를 사용해 간접 호출해야한다. ES6에서는 이러한 번거로움을 해결하기 위해 Rest 파라미터를 도입해 아래의 예제와 같은 방법으로 할 수 있다.

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


caller 프로퍼티
caller 프로퍼티는 ECMAScript 사양에 포함되지 않은 비표준 프로퍼티다. 이후 표준화될 예정도 없기 때문에 참고만 하도록 한다. caller 프로퍼티는 함수 자신을 호출한 함수를 가리킨다.

function foo(func){
  return func();
}
 
function bar(){
 return 'caller:'+bar.caller; 
}
 
console.log(foo(bar)); // caller :function foo(func){...}
console.log(bar()); //caller : null


length 프로퍼티
length는 프로퍼티 함수를 정의할 때 선언한 매개변수의 개수를 가리킨다.
다만 arguments 객체의 length프로퍼티와 함수 객체의 length프로퍼티의 값은 다를 수 있으므로 주의한다.

function foo(){
  console.log(foo.length); //0
}
 
function bar(x){
 console.log(bar.length); //1
}
 
function baz(x,y){
 console.log(baz.length); //2
}


name 프로퍼티
함수 객체의 name 프로퍼티는 함수 이름을 나타낸다. ES6 이전까지 비표준이었다가 ES6에서 정식 표준이 되었다. 그렇기 때문에 ES5와 ES6에서 동작이 달라지니 주의한다.

var namedFunc = function foo(){};
console.log(namedFunc.name); //foo
 
var anonymousFunc = function(){};
console.log(anonymousFunc.name); //anonymousFunc
 
var bar(){};
console.log(bar.name); //bar


proto접근자 프로퍼티
모든 객체는 [[Prototype]]이라는 내부 슬롯을 갖는다. 객체 지향 프로그래밍의 상속을 구현하는 프로토타입 객체를 가리킨다.  __proto 프로퍼티는 [[Prototype]]내부 슬롯이 가리키는 프로토타입 객체에 접근하기 위해 사용하는 접근자 프로퍼티다. [[Prototype]] 내부 슬롯에는 직접 접근할 수 없고 __proto를 통한 경우에 한하여 접근할 수 있다.

const obj = {a:1};
 
//객체 리터럴 방식으로 생성한 객체의 프로토타입 객체는 Object.prototype이다.
console.log(obj.__proto__ === Object.prototype); //true
 
//객체 리터럴 방식으로 생성한 객체는 프로토타입 객체인 Object.prototype의 프로퍼티를 상속받는다.
//hasOwnProperty 메서드는 Object.prototype의 메서드다.
console.log(obj.hasOwnProperty('a')); //true
console.log(obj.hasownProperty('__proto__')); //false


prototype 프로퍼티
prototype 프로퍼티는 생성자 함수로 호출할 수 있는 함수 객체, 즉 constructor만이 소유하는 프로퍼티다. 일반 객체 생성자 함수로 호출할 수 없는 non-constructor에는 prototype 프로퍼티가 없다.
prototype 프로퍼티는 함수가 객체를 생성하는 생성자 함수로 호출될 때 생성자 함수가 생성할 인스턴스의 프로토타입 객체를 가리킨다.