JavaScript/Basics

[JavaScript] new 연산자와 생성자 함수

Sonny Cucumber 2022. 3. 11. 14:16

객체 리터럴 {...}을 사용하면 객체를 쉽게 만들 수 있습니다. 그런데 개발을 하다보면

유사한 객체를 여러 개 만들어야 할 때가 생기곤 합니다. 복수의 사용자, 메뉴 내 다양한 아이템을

객체로 표현하려고 하는 경우가 그렇죠.

 

'new' 연산자와 생성자 함수를 사용하면 유사한 객체 여러 개를 쉽게 만들 수 있다.

생성자 함수

생성자 함수(constructor function)와 일반 함수에 기술적인 차이는 없습니다.

다만 생성자 함수는 아래 두 관례를 따릅니다.

  1. 함수 이름의 첫글자는 무조건 대문자
  2. 반드시 'new' 연산자를 붙여 실행합니다.

예시:

function User(name) {
  this.name = name;
  this.isAdmin = false;
}

let user = new User("보라");

alert(user.name); // 보라
alert(user.isAdmin); // false

new User(...)를 써서 함수를 실행하면 아래와 같은 알고리즘이 동작하는데,

  1. 빈 객체를 만들어 this에 할당합니다.
  2. 함수 본문을 실행합니다. this에 새로운 프로퍼티를 추가해 this를 추가합니다.
  3. this를 반환합니다.

예시를 이용해 new User(...)가 실행되면 무슨 일이 일어나는지 살펴보자

function User(name) {
  // this = {};  (빈 객체가 암시적으로 만들어짐)

  // 새로운 프로퍼티를 this에 추가함
  this.name = name;
  this.isAdmin = false;

  // return this;  (this가 암시적으로 반환됨)
}

이제 let user = new User("보라")는 아래 코드를 입력한 것과 동일하게 작동합니다.

let user = {
  name: "보라",
  isAdmin: false
};

이렇게 하는 방법이 객체 리터럴 문법으로 일일이 객체를 만드는 방법보다

훨씬 간단하고 읽기 쉽게 객체를 만들 수 있게 된다.

 

생성자의 의의는 바로 여기에 있다. 재사용할 수 있는 객체 생성 코드를 구현하는 것이죠.

 

잠깐! 모든 함수는 생성자 함수가 될 수 있다는 점을 잊지 말자.  new를 붙여 실행한다면 어떤 함수라도

위에 언급된 알고리즘이 실행된다. 이름의 '첫 글자가 대문자'인 함수는 new를 붙여 실행해야 한다는 점도 잊지말자

 

중요!  new function() {...}

재사용할 필요가 없는 복잡한 객체를 만들어야 한다고 보자. 많은 양의 코드가 필요할거다.

이럴 땐 아래와 같이 코드를 익명 생성자 함수로 감싸주는 방식을 사용할 수 있다.

 

아래 생성자 함수는 익명 함수이기에 어디에도 저장되지 않는다. 처음 만들 때부터 단 한번만 호출할 

목적으로 만들었기에 재사용이 불가능하다. 이렇게 익명 생성자 함수를 이용하면 재사용은 막으면서 코드 캡슐화 가능.

let user = new function() {
  this.name = "John";
  this.isAdmin = false;

  // 사용자 객체를 만들기 위한 여러 코드.
  // 지역 변수, 복잡한 로직, 구문 등의
  // 다양한 코드가 여기에 들어갑니다.
};

생성자와 return 문

생성자 함수엔 보통 리턴문이 없다. 반환해야할 것들은 모두 this에 저장되고, this는 자동으로

반환되기 때문에 반환문을 명시적으로 써 줄 필요가 없다.

그런데 만약 리턴문이 있다면 어떤 일이 벌어질까? 아래와 같은 간단한 규칙이 적용된다.

  • 객체를 리턴한다면 this대신 객체가 반환
  • 원시형을 return한다면 return문이 무시.

리턴 뒤에 객체가 오면 생성자 함수는 해당 객체를 반환해주고, 이 외의 경우는 this가 반환된다.

function BigUser() {

  this.name = "원숭이";

  return { name: "고릴라" };  // <-- this가 아닌 새로운 객체를 반환함
}

alert( new BigUser().name );  // 고릴라

첫번째 규칙이 적용된 예시. return은 this를 무시하고 객체를 반환

function SmallUser() {

  this.name = "원숭이";

  return; // <-- this를 반환함
}

alert( new SmallUser().name );  // 원숭이

아무것도 하지 않은 예시. 원시형을 반환하는 경우와 마찬가지로 두번째 규칙이 적용된다.

리턴문이 있는 생성자 함수는 거의 없다. 여기선 특이 케이스를 소개.

중요 - 괄호 생략하기

인수가 없는 생성자 함수는 괄호를 생략해 호출할 수 있습니다.

명세서(specification)에는 괄호를 생략해도 된다고 정의되지만 좋은 스타일은 아님

let user = new User; // <-- 괄호가 없음
// 아래 코드는 위 코드와 똑같이 동작합니다.
let user = new User();

생성자 내 메서드

생성자 함수를 사용하면 매개변수를 이용해 객체 내부를 자유롭게 구성 가능. 

지금까진 this에 프로퍼티를 더해주는 예시만 살펴봤는데, 메서드를 더해주는 것도 가능

아래 예시에서 new User(name)는 프로퍼티 name과 메서드 sayHi를 가진 객체를 만들어준다.

function User(name) {
  this.name = name;

  this.sayHi = function() {
    alert( "제 이름은 " + this.name + "입니다." );
  };
}

let bora = new User("이보라");

bora.sayHi(); // 제 이름은 이보라입니다.

/*
bora = {
   name: "이보라",
   sayHi: function() { ... }
}

 

'JavaScript > Basics' 카테고리의 다른 글

[JavaScript] 심볼형  (0) 2022.03.11
[JavaScript] 옵셔널 체이닝 '?.'  (0) 2022.03.11
[JavaScript] 메서드와 this  (0) 2022.03.11
[JavaScript] 가비지 컬렉션  (0) 2022.03.11
[JavaScript] 참조에 의한 객체 복사  (0) 2022.03.11