자바스크립트에서 함수는 '코드의 실행'뿐만 아니라 함수 자체가 객체처럼 프로퍼티(property)를 가질 수 있다.
- 함수를 생성할 때, 함수 코드는 함수 객체의 [[Code]] 내부 프로퍼티에 저장된다.
- 함수는 프로퍼티를 가질 수 있다.
- 함수는 일반 객체와는 달리 특정 기능의 코드를 수행할 수 있을 뿐만 아니라, 일반 객체처럼 프로퍼티를 가질 수 있는 특별한 객체이다.
다음 예제를 통해 이를 살펴보자.
function a() {
return 0;
}
a.b = 0;
a.c = 1;
a(); // 0
a.b; // 0
a.c; // 1
이처럼 여기서 생성한 a라는 함수는 코드의 실행뿐 아니라 b와 c라는 프로퍼티도 또한 가질 수 있다.
자바스크립트에서 함수는 객체로 취급된다고 언급했다. 따라서 우린 함수를 값으로도 사용할 수 있다. 자바스크립트에서 함수는 다음과 같은 동작이 가능하다.
- 리터럴에 의해 생성
- 변수 등에 할당 가능
- 함수의 인자로 전달가능
- 함수의 리턴값으로 리턴 가능
이와 같은 특징을 가지고 있는 함수를 일급 객체(First Class)라고 하며, 자바스크립트에서 함수는 일급 객체이다.
다음 예시는 자바스크립트의 함수가 일급 객체라는 것을 보인다.
var a = function() {
return 0;
}
a(); // 0
function b() {
return 0;
}
function a(func) {
return func();
}
a(b); // 0
function a() {
return function() {
return 0;
}
}
a()(); // 0
함수는 알반 객체와 다르게, 함수 객체만의 표준 프로퍼티가 정의되어 있다.
ECMA 표준
- length - 함수가 실행될 때 기대되는 인자의 개수를 나타낸다.
- prototype property - 함수가 생성자로 사용될 때, 이 함수로 생성된 객체의 부모 프로토타입 객체를 나타낸다.
다음은 ECMA 표준 프로퍼티가 아니다.
- name - 함수의 이름을 나타낸다.
- caller - 자신의 호출한 함수를 나타낸다.
- arguments - 함수를 호출할 때 전달된 인자값을 나타낸다.
- __proto__ ([[Prototype]] property != Prototype property) - 자신의 부모 프로토타입 객체를 나타낸다.
다음 예시를 통해 기본 프로퍼티를 알아보자.
ƒ plus(x, y) {
return x + y;
}
여기서 함수 객체의 __proto__ 즉, 함수 객체의 부모 프로토타입이 무엇인지 궁금할 것이다. 함수 객체의 부모 역할을 하는 프로토타입 객체는 'Function.prototype 객체'라고 한다. 이는 아무 이름이 없는 함수이고, 따라서 name 프로퍼티는 아무 값을 가지지 않는다.
Prototype 프로퍼티는 함수가 생성될 때 만들어지며, constructor 프로퍼티 만을 가지고 있는 객체를 가리킨다. 이때 constructor 프로퍼티는 함수 객체를 가리킨다. 함수 객체에서 Prototype 프로퍼티가 이 프로토타입 객체를 가리키므로 이는 서로를 참조하게 되는 꼴이다.
자바스크립트 함수 표현식에서 함수 이름은 꼭 붙이지 않아도 되고, 이를 익명 함수라고 부른다.
var a = function() //익명 함수 {
return 0;
}
이러한 익명 함수의 대표적인 활용은 바로 '콜백 함수'다. 콜백 함수는 어떤 이벤트가 발생하면 시스템에서 호출되는 함수를 말한다. 또한, 특정 함수에 인자로 넘겨져서 호출되는 함수도 콜백 함수라 한다.
이 콜백 함수의 대표적인 활용 예시는 다음과 같다.
<script>
window.onload = function() {
console.log("load!");
}
</script>
window.onload는 이벤트 핸들러이고, 이 이벤트 핸들러에 익명 함수를 연결했다. 웹 페이지가 로드되는 이벤트가 발생한다면 console.log를 실행하게 된다.
즉시 실행 함수는 함수를 정의함과 동시에 실행하는 함수이다. 다음 예시를 보자.
(function(str) {
console.log(str);
})("Hello");
이렇게 선언되자마자 실행되도록 만든 즉시 실행 함수는 다시 호출이 불가능하다. 따라서 최초 한 번만 실행하는 함수를 사용할 때 유용하다. 예를 들어, 라이브러리의 초기화(한 번만 실행) 코드를 즉시 실행 함수를 사용하여 구현한다면, 변수 명의 중복 문제를 해결할 수 있어 유용하다.
자바스크립트는 함수 코드 내부에 또다시 함수 정의가 가능하다. 이렇듯 함수 내부에 정의된 함수를 '내부 함수(Inner function)'이라고 한다. 다음 예시를 보자.
function a() {
var i = 0;
var j = 1;
function b() {
var i = 1;
console.log(i); // 1
console.log(j); // 1
}
b();
}
b(); // error
내부 함수는 자바스크립트의 '스코프 체이닝'과 함께 특별한 기능을 한다. 여기서 b함수에서 i를 호출할 때 b함수 바깥에 있는 i가 아닌, b함수 안에 있는 i가 출력이 되었다. 또한 b함수는 j를 가지고 있지 않지만 j를 출력해주었다. 이는 b함수 밖의 j를 참조하여 출력하는 과정이 있다. 스코프 체이닝 덕분에 함수 밖에서 선언된 변수나 함수에 접근이 가능한 것이다.
맨 마지막 b함수를 b함수가 정의된 a함수 바깥에서 호출하는 코드가 있는데, 이는 오류를 발생시킨다. b함수의 스코프가 a함수 안이기 때문에 이런일이 발생하는 것이다. 하지만 외부에서 내부 함수에 접근할 수 있는 방법이 있다. 다음 예시를 보자.
function a() {
var i = 0;
var b = function() {
return i;
}
return b;
}
var c = a();
c(); // 0
자바스크립트에서의 함수는 일급 객체다. 따라서, 함수를 리턴값으로 사용할 수 있다. a함수는 내부 함수b의 '참조값'을 반환한다. 이를 변수 c에 저장하고 c를 호출한다면, b함수가 실행된다. 외부에서 내부 함수를 실행한 것이다. 또한 여기서 a함수 내부의 변수 i를 외부로 끄집어 낸 것을 알 수 있는데, 이렇게 부모 함수 스코프의 변수를 참조하는 b함수를 '클로저'라 부른다.