생성자 함수란, 새로운 객체(인스턴스)를 생성하고 초기화하기 위해 사용하는 특별한 함수를 말한다.
일반 함수처럼 생겼지만, new 키워드를 붙여 호출하면 동작 방식이 달라진다.
보통 함수 이름은 대문자로 시작한다.
내부에서 this를 사용해 새로 생성되는 객체에 속성과 메서드를 정의한다.
-> 객체를 찍어내는 '틀'이다.
function Animal(type, sound) {
this.type = type;
this.sound = sound;
}
const dog = new Animal("개", "멍멍");
const cat = new Animal("고양이", "야옹");
console.log(dog.type); // "개"
console.log(cat.sound); // "야옹"
new 키워드를 붙였을 때 함수 내부에서 벌어지는 과정은 다음 4단계와 같다.
예시를 보자
function User(name) {
// this = {}; (빈 객체가 암시적으로 만들어짐)
// 새로운 프로퍼티를 this에 추가함
this.name = name;
this.isAdmin = false;
// return this; (this가 암시적으로 반환됨)
}
new User("보라")이외에도 new User("호진"), new User("지민") 등을 이용하면 손쉽게 사용자 객체를 만들 수 있다.
객체 리터럴 문법으로 일일이 객체를 만드는 방법보다 훨씬 간단하고 읽기 쉽게 객체를 만들 수 있게 된다.
생성자의 의의는 바로 여기에 있다. 재사용할 수 있는 객체 생성 코드를 구현하는 것이다.
위에서 본 것처럼 생성자 함수엔 보통 return 문이 없다. 반환해야 할 것들은 모두 this에 저장되고, this는 자동으로 반환되기 때문이다.
그런데 만약 return 문이 있다면 어떻게 될까?
아래와 같은 규칙이 적용된다.
function BigUser() {
this.name = "원숭이";
return { name: "고릴라" }; // <-- this가 아닌 새로운 객체를 반환함
}
console.log( new BigUser().name ); // 고릴라
function SmallUser() {
this.name = "원숭이";
return 10; // <-- return문 무시하고 this를 반환함
return; // <-- return문 무시하고 this를 반환함
}
console.log( new SmallUser().name ); // 원숭이
하지만 걱정마시라 보통의 생성자 함수에는 return 문이 없다!
객체 리터럴이란, 중괄호 {}를 사용하여 직접 객체를 생성하고 속성(key)과 값(value)을 한 번에 정의하는 방법을 말한다.
const user = {
name: "민준",
age: 25,
greet: function () {
console.log("안녕하세요!");
}
};
| 구분 | 객체 리터럴 {} | 생성자 함수 new + 함수 |
|---|---|---|
| 작성 방식 | 중괄호 {} 안에 직접 속성과 값을 작성한다. | 함수를 정의하고 new 키워드로 호출한다. |
| 객체 생성 방법 | 객체를 하나하나 직접 만든다. | 함수 호출을 통해 객체를 찍어낸다. |
| 코드 재사용 | 비슷한 객체를 만들려면 매번 복사해서 작성해야 한다. | 함수를 통해 같은 구조의 객체를 쉽게 여러 개 만들 수 있다. |
| 확장성 | 객체가 늘어날수록 코드가 길어지고 복잡해진다. | 생성자 함수 하나만 있으면 많은 객체를 효율적으로 생성할 수 있다. |
| 프로토타입 사용 가능 여부 | 직접 작성한 객체마다 별도로 메서드를 추가해야 한다. | 프로토타입을 활용해 메서드를 공유할 수 있다. |
prototype이란?
prototype이란,
모든 자바스크립트 객체가 가지고 있는 숨겨진 참조 링크(속성)로,
공통되는 속성이나 메서드를 공유하기 위해 사용된다.
쉽게 말하면
객체끼리 공통으로 사용할 기능을 prototype에 올려놓고
각 객체들은 그걸 공유해서 쓰는 구조다.
예시
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log(`안녕하세요, ${this.name}입니다.`);
};
const MJ = new Person("민준");
MJ.sayHello(); // "안녕하세요, 민준입니다."
Person이라는 생성자 함수안에서 sayHello() 라는 함수를 넣은적이 없는데 변수 MJ는 sayHello() 함수를 호출할 수 있다.
결론적으로 생성자함수는
비슷한 객체를 쉽게 찍어낼 수 있다.
→ 매번 객체를 새로 만들 필요 없이, 생성자 함수를 호출만 하면 된다.
코드 재사용이 가능하다.
→ 하나의 생성자 함수만 만들어두면, 같은 형태의 객체를 무한히 만들 수 있다.
초기화 과정을 자동화할 수 있다.
→ 생성자 함수 안에 초기값 설정 코드를 넣어, 객체마다 값을 다르게 줄 수 있다.
prototype을 활용해 메서드를 공유할 수 있다.
→ 메모리를 아끼면서 객체들끼리 공통 기능을 사용할 수 있다.
코드가 구조화되고 유지보수가 쉬워진다.
→ 객체의 설계도(생성자 함수)와 객체 생성(인스턴스화) 과정을 분리할 수 있다.