함수도 객체다
함수는 호출 가능한 객체(callable object)로서, 일반 객체처럼 프로퍼티를 가질 수 있습니다. 이를 통해 함수 자체에 데이터를 저장하거나 상태를 관리할 수 있습니다.
function sayHello() {
console.log("안녕하세요!");
}
// 함수의 내장 프로퍼티 확인
console.log(sayHello.name); // 출력: "sayHello"
console.log(sayHello.length); // 출력: 0 (매개변수의 수)
// 사용자 정의 프로퍼티 추가
sayHello.counter = 0;
// 함수 호출과 프로퍼티 활용
sayHello(); // 출력: 안녕하세요!
sayHello.counter++;
console.log(`sayHello 함수는 총 ${sayHello.counter}번 호출되었습니다.`);
// 출력: sayHello 함수는 총 1번 호출되었습니다.
위 예제에서 sayHello 함수에 counter라는 사용자 정의 프로퍼티를 추가하여 호출 횟수를 추적하고 있습니다. 이는 함수가 객체이기 때문에 가능한 일이며, 함수의 동작과 상태를 결합하여 관리할 수 있습니다.
함수의 내장 프로퍼티: name과 length
name 프로퍼티
함수 선언문이나 함수 표현식에 의해 만들어진 함수는 자동으로 자신의 이름을 기억합니다. 익명 함수라도 할당된 변수의 이름을 통해 이름이 추론될 수 있습니다.
// 익명 함수 표현식
let greet = function() {
console.log("안녕하세요!");
};
console.log(greet.name); // 출력: "greet"
length 프로퍼티
함수의 length 프로퍼티는 함수 선언 시 정의된 매개변수의 개수를 나타냅니다. 여기에는 나머지 매개변수(rest parameters)는 포함되지 않습니다.
function add(a, b, ...rest) {
return a + b;
}
console.log(add.length); // 출력: 2
기명 함수 표현식
기명 함수 표현식은 함수 표현식에 이름을 부여하여, 함수 내부에서 자기 자신을 참조할 수 있게 합니다. 이는 재귀 호출 등에서 유용하게 사용됩니다.
let factorial = function computeFactorial(n) {
if (n <= 1) {
return 1;
} else {
return n * computeFactorial(n - 1);
}
};
console.log(factorial(5)); // 출력: 120
// 외부에서는 'computeFactorial' 이름으로 함수에 접근할 수 없습니다.
try {
computeFactorial(5); // ReferenceError 발생
} catch (error) {
console.error(error.message); // 출력: computeFactorial is not defined
}
위 예제에서 함수 표현식에 이름 computeFactorial을 부여하여 내부에서 자기 자신을 재귀적으로 호출합니다. 그러나 이 이름은 함수 내부에서만 유효하며, 외부 스코프에서는 접근할 수 없습니다. 이를 통해 외부 변수에 의존하지 않고 자기 자신을 참조할 수 있습니다.
함수 프로퍼티를 이용한 상태 관리
함수는 클로저(closure)를 사용하여 외부 변수를 기억할 수 있지만, 함수 자체에 프로퍼티를 추가하여 상태를 관리하는 방법도 있습니다.
function makeCounter() {
function counter() {
return counter.count++;
}
counter.count = 0; // 함수 프로퍼티로 초기값 설정
return counter;
}
let counter1 = makeCounter();
console.log(counter1()); // 출력: 0
console.log(counter1()); // 출력: 1
// 함수 프로퍼티에 직접 접근하여 수정 가능
counter1.count = 10;
console.log(counter1()); // 출력: 10
이 방식은 외부에서 함수 프로퍼티에 직접 접근하여 값을 변경할 수 있으므로 잠재적인 위험이 있습니다.
클로저와의 비교
클로저를 사용하면 외부에서 변수에 직접 접근할 수 없으므로 데이터의 은닉성(encapsulation)을 보장할 수 있습니다.
function createCounter() {
let count = 0;
return function() {
return count++;
};
}
let counter2 = createCounter();
console.log(counter2()); // 출력: 0
console.log(counter2()); // 출력: 1
// 외부에서 'count' 변수에 접근 불가
console.log(typeof count); // 출력: undefined
함수 객체적을 이용한 캐싱
function fibonacci(n) {
// 캐시 초기화
if (!fibonacci.cache) {
fibonacci.cache = {};
}
// 캐시에 결과가 있으면 반환
if (fibonacci.cache[n]) {
return fibonacci.cache[n];
}
// 계산 및 캐싱
if (n <= 1) {
fibonacci.cache[n] = n;
} else {
fibonacci.cache[n] = fibonacci(n - 1) + fibonacci(n - 2);
}
return fibonacci.cache[n];
}
console.log(fibonacci(10)); // 출력: 55
위 예제에서 fibonacci 함수는 자신의 프로퍼티 cache를 사용하여 이미 계산된 값을 저장하고 필요할 때 재사용합니다.
'JavaScript' 카테고리의 다른 글
[JavaScript] setTimeout과 setInterval (0) | 2025.02.13 |
---|---|
[JavaScript] new Function 문법 (0) | 2025.02.13 |
[JavaScript] 전역 객체 및 전역 변수 관리 (0) | 2025.02.13 |
[JavaScript] var의 특징 (0) | 2025.02.13 |
[JavaScript] 변수의 스코프와 클로저 (0) | 2025.02.13 |