자바스크립트에서는 함수가 **일급 객체(First-Class Object)**로 취급된다. 이는 함수를 변수에 할당하거나, 인자로 전달하고, 반환값으로 사용할 수 있다는 것을 의미한다.
일급 객체는 다음과 같은 특징을 가진다.
- 변수나 데이터 구조에 할당 가능
- 함수를 변수에 저장할 수 있다.
- 함수를 인자로 전달 가능
- 함수의 매개변수로 다른 함수를 전달할 수 있다.
- 함수를 반환값으로 사용 가능
- 함수에서 다른 함수를 반환할 수 있다.
- 동적으로 프로퍼티를 추가 가능
- 함수는 객체처럼 동작하므로, 프로퍼티를 동적으로 추가할 수 있다.
- 익명(Anonymous)으로 생성 가능
- 반드시 이름을 가질 필요 없이 익명 함수로 선언할 수 있다.
(1) 변수에 할당
const sayHello = function() {
return "Hello, world!";
};
console.log(sayHello()); // Hello, world!(2) 함수의 인자로 전달
function executeFunction(fn) {
console.log(fn());
}
executeFunction(sayHello); // Hello, world!(3) 함수의 반환값으로 사용
function createMultiplier(factor) {
return function (x) {
return x * factor;
};
}
const double = createMultiplier(2);
console.log(double(5)); // 10(4) 동적으로 프로퍼티 추가
function myFunc() {}
myFunc.customProperty = "I'm a function property!";
console.log(myFunc.customProperty); // I'm a function property!(5) 익명 함수 사용
const add = function(a, b) {
return a + b;
};
console.log(add(3, 4)); // 7- 고차 함수(Higher-Order Function) 구현 가능
- 함수가 다른 함수를 인자로 받거나 반환할 수 있어 콜백 함수나 **커링(curring)**이 가능하다.
- 함수형 프로그래밍 스타일 지원
map,filter,reduce등의 배열 메서드를 활용하여 선언형 프로그래밍을 할 수 있다.
- 클로저(Closure) 구현 가능
- 내부 함수가 외부 함수의 스코프에 접근할 수 있어 데이터 은닉과 상태 유지가 가능하다.
자바스크립트에서 함수는 **객체(Object)**이므로 프로퍼티를 가질 수 있다.
일반적인 객체처럼 동적으로 프로퍼티를 추가할 수도 있고, 함수 객체가 기본적으로 제공하는 프로퍼티들도 존재한다.
| 프로퍼티 | 설명 |
|---|---|
length |
함수가 기대하는 매개변수(parameter) 개수 |
name |
함수의 이름 (익명 함수의 경우 빈 문자열 "") |
prototype |
생성자 함수에서 새로운 객체의 프로토타입을 가리킴 |
caller |
현재 함수가 호출된 직전 함수 (비권장) |
arguments |
함수에 전달된 인자 정보 (비권장, arguments 객체 사용) |
length 프로퍼티는 함수를 선언할 때 정의한 매개변수의 개수를 나타낸다.
function sum(a, b) {
return a + b;
}
console.log(sum.length); // 2 (매개변수 개수)rest parameter(...)는 개수에 포함되지 않는다.
function logAll(...args) {
console.log(args);
}
console.log(logAll.length); // 0 (rest parameter는 개수에 포함되지 않음)함수의 이름을 문자열로 반환한다.
function greet() {}
const sayHello = function() {};
const arrowFunc = () => {};
console.log(greet.name); // "greet"
console.log(sayHello.name); // "sayHello"
console.log(arrowFunc.name); // "arrowFunc"익명 함수는 빈 문자열("")을 반환한다.
console.log((function() {}).name); // ""모든 함수는 prototype 프로퍼티를 가지며, 이는 객체의 원형(prototype chain)을 구성할 때 사용된다.
일반 함수에는 prototype이 존재하지만, 화살표 함수에는 없다.
function Person(name) {
this.name = name;
}
console.log(Person.prototype); // {constructor: ƒ}
console.log(typeof Person.prototype); // "object"
// 화살표 함수에는 prototype이 없음
const Arrow = () => {};
console.log(Arrow.prototype); // undefined__proto__는 모든 객체가 가지고 있는 비공식적인 프로퍼티로, 해당 객체의 프로토타입(prototype)을 참조한다. 즉, 객체가 상속받은 프로토타입 체인을 탐색할 때 사용된다.
JavaScript에서 prototype과 __proto__는 둘 다 객체 간의 상속 관계와 관련이 있지만, 서로 다른 목적과 사용법을 가지고 있습니다.
prototype은 함수 객체가 가지는 프로퍼티로, 해당 함수를 통해 생성될 객체의 프로토타입(원형)을 가리킵니다. 즉, 생성자 함수가 인스턴스를 만들 때 그 인스턴스에게 물려줄 속성과 메서드를 정의하는 객체입니다.
__proto__는 모든 객체가 가지는 내부 프로퍼티로, 해당 객체가 생성될 때 사용된 생성자 함수의 prototype 객체를 가리킵니다. 이는 객체의 프로토타입 체인을 형성하는 링크 역할을 합니다.
- 소유 주체:
prototype: 함수 객체만 가지는 프로퍼티__proto__: 모든 JavaScript 객체가 가지는 프로퍼티
- 목적:
prototype: 새로 생성될 객체에게 상속할 속성과 메서드 정의__proto__: 객체가 자신의 프로토타입을 참조하기 위한 링크
- 사용 방식:
prototype: 생성자 함수에서 직접 접근하여 프로퍼티와 메서드 정의__proto__: 객체의 프로토타입 체인을 통해 속성을 찾을 때 사용되는 내부 메커니즘
- 표준화:
prototype: 초기부터 JavaScript의 공식 명세에 포함__proto__: 원래는 비표준이었으나 널리 사용되어 ES6에서 레거시 기능으로 표준화됨
// 생성자 함수 정의
function Person(name) {
this.name = name;
}
// Person.prototype에 메서드 추가
Person.prototype.sayHello = function() {
console.log(`안녕하세요, 제 이름은 ${this.name}입니다.`);
};
// 인스턴스 생성
const hong = new Person('홍길동');
// 프로토타입 관계 확인
**console.log(Person.prototype === hong.__proto__); // true**
// 메서드 호출
hong.sayHello(); // "안녕하세요, 제 이름은 홍길동입니다."위 예제에서:
Person.prototype은Person생성자 함수가 가지는 프로퍼티로, 모든Person인스턴스가 공유할 메서드와 속성을 정의합니다.hong.__proto__는hong객체의 프로토타입을 가리키며, 이는Person.prototype과 동일합니다.hong.sayHello()를 호출하면 JavaScript 엔진은 먼저hong객체에서sayHello메서드를 찾고, 없으면hong.__proto__(즉,Person.prototype)에서 찾습니다.
__proto__는 레거시 기능으로, 최신 JavaScript에서는 아래와 같은 방법을 권장합니다:
- 객체의 프로토타입을 읽을 때:
Object.getPrototypeOf(obj) - 객체의 프로토타입을 설정할 때:
Object.setPrototypeOf(obj, prototype) - 특정 프로토타입을 가진 객체 생성:
Object.create(prototype)
이러한 방법을 사용하면 더 명시적이고 안전하게 프로토타입 관련 작업을 수행할 수 있습니다.
__proto__vsprototype차이점
| 프로퍼티 | 설명 |
|---|---|
__proto__ |
모든 객체가 가지고 있는 프로토타입 참조 (비표준 속성) |
prototype |
함수 객체만 가지고 있으며, 생성된 객체의 프로토타입이 됨 |
caller 프로퍼티는 어떤 함수가 현재 함수를 호출했는지를 나타낸다.
하지만 strict mode에서는 사용이 제한되므로 권장되지 않는다.
function first() {
second();
}
function second() {
console.log(second.caller); // first 함수가 출력됨
}
first();Error.stack을 활용하는 것이 더 좋다.
arguments 객체는 함수 내에서 사용 가능하며, 전달된 모든 인자를 배열 형태로 제공한다.
(단, 화살표 함수에서는 사용할 수 없다.)
function printArgs() {
console.log(arguments);
}
printArgs(1, 2, 3);
// [Arguments] { '0': 1, '1': 2, '2': 3 }arguments 대신 rest parameter (...args)를 사용하는 것이 좋다.
function printArgs(...args) {
console.log(args); // [1, 2, 3]
}
printArgs(1, 2, 3);자바스크립트의 함수는 객체이므로, 임의의 프로퍼티를 추가할 수도 있다.
function myFunction() {}
myFunction.customProperty = "Hello!";
console.log(myFunction.customProperty); // "Hello!"이 기능을 활용하면 캐싱 같은 패턴도 구현할 수 있다.
function memoizedFactorial(n) {
if (n === 0) return 1;
if (!memoizedFactorial.cache) {
memoizedFactorial.cache = {};
}
if (memoizedFactorial.cache[n]) {
return memoizedFactorial.cache[n];
}
return memoizedFactorial.cache[n] = n * memoizedFactorial(n - 1);
}
console.log(memoizedFactorial(5)); // 120
console.log(memoizedFactorial.cache); // { '5': 120, '4': 24, '3': 6, '2': 2, '1': 1 }- 자바스크립트의 함수는 객체이므로 프로퍼티를 가질 수 있다.
- 기본 제공 프로퍼티:
length→ 매개변수 개수name→ 함수 이름prototype→ 생성자 함수에서 사용caller→ 호출한 함수 (비권장)arguments→ 전달된 인자 정보 (비권장)
- 동적으로 프로퍼티 추가 가능, 이를 활용해 캐싱 등의 기능을 구현할 수 있다.