4. 함수와 프로토타입 체이닝 #2 함수 객체 : 함수도 객체다

2021. 7. 22. 16:34JavaScript/basic

본 글은 인사이드 자바스크립트 도서의 내용을 복습하기 위해 작성된 글입니다.

4.2 함수 객체 : 함수도 객체다

4.2.1 자바스크립트에서는 함수도 객체다

자바스크립트에서는 함수도 객체다. 즉, 함수의 기본 기능인 코드 실행뿐만 아니라, 함수 자체가 일반 객체처럼 프로퍼티들을 가질 수 있다는 것이다.

 

add() 함수도 객체처럼 프로퍼티를 가질 수 있다.

// add() 함수도 객체처럼 프로퍼티를 가질 수 있다.
// 함수 선언 방식으로 add() 함수 정의
function add(x,y){
    return x+y;
}

// add() 함수 객체에 result, status 프로퍼티 추가
add.result = add(2,3);
add.status = "OK";

console.log(add.result);    // 5
console.log(add.status);    // OK
console.dir(add)

add() 함수의 프로퍼티를 확인하면 result, status 프로퍼티가 저장된 것을 확인할 수 있다.

 

add() 함수 객체

 

4.2.2 자바 스크립트에서 함수는 값으로 취급된다

자바스크립트 함수를 가지고 가능한 동작

  1. 리터럴에 의해 생성
  2. 변수나 배열의 요소, 객체의 프로퍼티 등에 할당 가능
  3. 함수의 인자로 전달 가능
  4. 함수의 리턴값으로 리턴 가능
  5. 동적으로 프로퍼티를 생성 및 할당 가능

위와 같은 특징을 가지는 함수를 일급 객체라고 부른다. 일급 객체인 함수는 객체, 배열 등에 값으로도 저장할 수 있으며, 다른 함수의 인자로 전달한다거나 함수의 리턴값으로도 사용 가능하다.

 

 

4.2.2.1 변수나 프로퍼티의 값으로 할당

함수는 숫자나 문자열처럼 변수나 프로퍼티의 값으로 할당될 수 있다.

 

변수나 프로퍼티에 함수값을 할당하는 코드

// 변수에 함수 할당
let foo = 100;
let bar = function(){return 100;};
console.log(bar()); // 100

// 프로퍼티에 함수 할당
let obj = {};
obj.baz = function(){return 200;};
console.log(obj.baz());     // 200

4.2.2.2 함수 인자로 전달

함수는 다른 함수의 인자로도 전달이 가능하다.

 

함수를 다른 함수의 인자로 넘긴 코드

// 함수 표현식으로 foo2() 함수 생성
let foo2 = function(func){
    func();
};

// foo2 함수 실행
foo2(function(){
    console.log("function can be used as the argument");
});

 

4.2.2.3 리턴값으로 활용

함수는 다른 함수의 리턴값으로도 활용할 수 있다.

 

함수를 다른 함수의 리턴값으로 활용한 코드

// 함수를 리턴하는 foo3() 함수 정의
let foo3 = function(){
    return function(){
        console.log("this function is the return value");
    };
};

foo3()();   // this functions is the return value

 

4.2.3 함수 객체의 기본 프로퍼티

일반 객체와는 다르게 추가로 함수 객체만의 표준 프로퍼티가 정의되어 있다.

  • length : 인자의 개수
  • prototype : 함수가 가지는 prototype 프로퍼티는 이 함수가 생성자로 사용될 때 이 함수를 통해 생된 객체와 부모 역할을 하는 프로토타입 객체를 가리킨다.
  • name : 함수의 이름
  • caller : 자신을 호출한 함수
  • arguments : 함수를 호출할 때 전달된 인자값들

add() 함수 객체 프로퍼티를 출력하는 코드

// add() 함수 객체 프로퍼티를 출력하는 코드
function add(x,y){
    return x+y;
}

console.dir(add);   // arguments, caller, length등과 같은 프로퍼티가 존재한다.

ECMA5 스크립트 명세서에는 모든 함수가 length와 prototype 프로퍼티를 가져야 한다고 기술하고 있다. 위의 실행결과를 살펴봤을 때 add() 함수 역시 length와 prototype 프로퍼티를 가지고 있는 것을 확인할 수 있다. 이 두 프로퍼티에 대해서는 아래에 설명할 예정이다.

 

우선, length나 prototype 이외의 name, caller, arguments, __proto__ 프로퍼티는 다음과 같다. name 프로퍼티는 함수의 이름을 나타낸다. 만약 이름이 없는 익명 함수라면 name 프로퍼티는 빈 문자열이 된다.

caller 프로퍼티는 자신을 호출한 함수를 나타낸다. arguments는 함수를 호출할 때 전달된 인자값을 나타낸다.

 

마지막으로 __proto__ 프로퍼티는 3.4 프로토타입에서 모든 자바스크립트 객체는 자신의 프로토타입을 가리키는 [[Prototype]]라는 내부 프로퍼티를 가진다고 설명하였다. 크롬 브라우저에서는 [[Prototype]]이라는 내부 프로퍼티가 바로 __proto__ 프로퍼티로 구현되어 있다. 즉, [[Prototype]]과 __proto__는 같은 의미이다.

 

add() 함수 역시 자바스크립트 객체이므로 [[Prototype]] 프로퍼티(__proto__ 프로퍼티)를 가지고 있고 이를 통해 자신의 부모 역할을 하는 프로토타입 객체를 가리킨다.

 

정리하면 Function.prototype 객체는 모든 함수들의 부모 역할을 하는 프로토타입 객체이다. Function.prototype 객체의 부모는 Object.prototype 객체이다.

 

4.2.3.1 length 프로퍼티

함수가 정상적으로 실행될 때 기대되는 인자의 개수를 나타낸다.

 

함수 객체의 length 프로퍼티

function fun0(){

}

function fun1(x){
    return x;
}

function fun2(x,y){
    return x+y;
}

function fun3(x,y,z){
    return x+y+z;
}

console.log("fun0.length : " + fun0.length);    // 0
console.log("fun1.length : " + fun1.length);    // 1
console.log("fun2.length : " + fun2.length);    // 2

4.2.3.2 prototype 프로퍼티

모든 함수는 객체로서 prototype 프로퍼티를 가지고 있다. 여기서 주의할 점은 함수 객체의 prototype 프로퍼티는 앞서 설명한 모든 객체의 부모를 나타내는 내부 프로퍼티인 [[Prototype]]과 혼동하지 말아야 한다.

 

더보기

prototype 프로퍼티와 [[Prototype]] 프로퍼티

두 프로퍼티 모두 프로토타입 객체를 가리킨다는 점에서는 공통점이 있지만. 관점에 차이가 있다. 모든 객체에 있는 내부 프로퍼티인 [[Prototype]]는 객체 입장에서 잣니의 부모 역할을 하는 프로토타입 객체를 가리키는 반면에,

함수 객체가 가지는 prototype 프로퍼티는 이 함수가 생성자로 사용될 때 이 함수를 통해 생성된 객체의 부모 역할을 하는 프로토타입 객체를 가리킨다.

 

prototype 프로퍼티는 함수가 생성될 때 만들어지며, 다음 그림과 같이 단지 constructor 프로퍼티 하나만 있는 객체를 가리킨다. 그리고 prototype 프로퍼티가 가리키는 프로토타입 객체의 유일한 constructor 프로퍼티는 자신과 연결된 함수를 가리킨다. 즉, 자바스크립트에서는 함수를 생성할 때, 자신과 연결된 프로토타입 객체를 동시에 생성하며, 이 둘은 다음 그림처럼 각각 prototype과 constructor라는 프로퍼티로 서로를 참조하게 된다.

 

함수 객체와 프로토타입 객체의 관계

함수 객체와 프로토타입 객체와의 관계를 보여주는 코드

function myFunction(){
    return true;
}
console.dir(myFunction.prototype);
console.dir(myFunction.prototype.constructor);

myFunction.prototype 객체는 constructor와 __proto__ 라는 두개의 프로퍼티가 있다. 이 객체는 myFunction() 함수의 프로토타입 객체이므로 constructor 프로퍼티가 있음을 확인할 수 있다.

또한 프로토타입 객체 역시 자바스크립트 객체이므로 예외없이 자신의 부모 역할을 하는 __proto__ 프로퍼티가 존재한다.

 

 

myFunction.prototype.constructor의 값을 출력함으로써 프로토타입 객체와 매핑된 함수를 알아볼 수 있다. 결과값을 보면 myFunction() 함수를 가리키고 있는 것을 확인할 수 있다.

 

myFunction() 함수 객체와 myFunction.prototype 프로토타입 객체의 관계

References

인사이드 자바스크립트, 송형주 저