2025. 6. 19. 09:00ㆍJavascript/Javascript
객체 리터럴 { ... }을 사용하면 객체를 쉽게 만들 수 있다. 하지만 개발을 하다 보면 유사한 객체를 여러 개 만들어야 할 때가 생기곤 하는데 이럴 때 new 연산자와 생성자 함수를 사용하면 편리하다.
생성자 함수
생성자 함수(constructor function)와 일반 함수에 기술적인 차이는 없다. 다만 생성자 함수의 경우 아래의 두 가지 관례를 따른다.
- 함수 이름의 첫 글자는 대문자로 작성한다.
- 반드시 'new' 연산자를 붙여 실행한다.
function User(name) {
this.name = name;
this.isAdmin = false;
}
let user = new User("John");
alert(user.name); // John
alert(user.isAdmin); // false
new User(...)와 같이 함수를 실행하면 아래와 같은 알고리즘이 동작한다.
- 빈 객체를 만들어 this에 할당한다.
- 함수 본문을 실행한다. this에 새로운 프로퍼티를 추가해 this를 수정한다.
- this를 반환한다.
예시를 통해 이 과정을 좀 더 자세히 살펴보자.
function User(name) {
// this = {}; (빈 객체가 암시적으로 만들어짐)
// 새로운 프로퍼티를 this에 추가함
this.name = name;
this.isAdmin = false;
// return this; (this가 암시적으로 반환됨)
}
let user = new User("John")은 아래 코드를 입력한 것과 동일하게 동작한다.
let user = {
name: "John",
isAdmin: false
};
그리고 이제 new User("John") 이외에도 new User("Kim"), new User("Lee") 등을 이용하면 편리하게 사용자 객체를 만들 수 있다. 객체 리터럴 문법으로 일일이 객체를 만드는 것보다 훨씬 간단하고 읽기 쉽게 객체를 만들 수 있게 된 것이다. 생성자의 의의는 바로 여기에 있다. 재사용할 수 있는 객체 생성 코드를 구현하는 것이다.
모든 함수는 생성자 함수가 될 수 있다. new 키워드를 붙여 실행한다면 어떤 함수라도 위에 언급된 알고리즘이 실행된다. 또한 이름의 첫 글자가 대문자인 함수는 new를 붙여 실행해야 한다는 점도 잊지 말자. 공동의 약속이기 때문이다.
한편 재사용할 필요가 없는 복잡한 객체를 만들어야 한다면 어떨까? 이럴 때에는 아래와 같이 코드를 익명의 생성자 함수로 감싸주는 방식을 사용할 수 있다.
let user = new function() {
this.name = "John";
this.isAdmin = false;
// 사용자 객체를 만들기 위한 여러 코드.
// 지역 변수, 복잡한 로직, 구문 등의 다양한 코드가 여기에 들어감.
};
위의 생성자 함수는 익명 함수이기 때문에 어디에도 저장되지 않는다. 처음 만들 때부터 단 한 번만 호출할 목적으로 만들었기 때문에 재사용도 불가능한다. 이렇게 익명 생성자 함수를 이용하면 재사용은 막으면서 코드를 캡슐화할 수 있다.
new.target과 생성자 함수
new.target 프로퍼티를 사용하면 함수가 new와 함께 호출되었는지 아닌지를 알 수 있다. 일반적인 방법으로 함수를 호출했다면 new.target은 undefined를 반환하며 new와 함께 호출된 경우 함수 자체를 반환해 준다.
function User() {
alert(new.target);
}
// 'new' 없이 호출함
User(); // undefined
// 'new'를 붙여 호출함
new User(); // function User { ... }
생성자와 return문
생성자 함수에는 보통 return문이 없다. 반환해야 할 것들은 모두 this에 저장되고 this는 자동으로 반환되기 때문에 return문을 명시적으로 써 줄 필요가 없는 것이다. 그런데 만약 return문이 있다면 어떤 일이 벌어질까? 아래와 같은 간단한 규칙들이 적용된다.
- 객체를 return한다면 this 대신 객체가 반환된다.
- 원시값을 return한다면 return문이 무시된다.
결국 return 뒤에 객체가 오면 해당 객체를 반환해 주고 이 외의 경우에는 this가 반환되는 것이다. 물론 return문이 있는 생성자 함수는 거의 없다.
// 객체 반환 예시
function BigUser() {
this.name = "원숭이";
return { name: "고릴라" }; // <-- this가 아닌 새로운 객체를 반환함
}
alert( new BigUser().name ); // 고릴라
// 아무것도 return하지 않은 경우
function SmallUser() {
this.name = "원숭이";
return; // <-- this를 반환함
}
alert( new SmallUser().name ); // 원숭이
생성자 내 메서드
생성자 함수를 사용하면 파라미터를 이용해 객체 내부를 자유롭게 구성할 수 있으므로 상당한 유연성이 확보된다고 할 수 있다. 지금까지는 this에 프로퍼티를 더해주는 예시들을 위주로 보았지만 메서드를 더해주는 것 또한 가능하다.
아래 예시에서 new User(name)는 프로퍼티 name과 메서드 sayHi를 가진 객체를 만들어 준다.
function User(name) {
this.name = name;
this.sayHi = function() {
alert( "제 이름은 " + this.name + "입니다." );
};
}
let bora = new User("John");
bora.sayHi(); // 제 이름은 John입니다.
/*
bora = {
name: "John",
sayHi: function() { ... }
}
*/
'Javascript > Javascript' 카테고리의 다른 글
[Javascript] 비구조화 할당(구조분해) (1) | 2025.06.23 |
---|---|
[Javascript] FormData (1) | 2025.06.20 |
[Javascript] async 함수의 병렬 처리 (1) | 2025.06.18 |
[Javascript] 가비지 컬렉션(Garbage Collection) (1) | 2025.06.17 |
[Javascript] 대기 함수 만들기 (1) | 2025.06.16 |