윤시의 블로그

[JavaScript] 자바스크립트 생성자 함수, 객체 생성 방식 본문

JavaScript

[JavaScript] 자바스크립트 생성자 함수, 객체 생성 방식

yo09 2025. 3. 14. 11:51

자바스크립트에서 객체를 생성하는 방법은 여러 가지가 있다.

그 중 두 가지 주요 방법은 객체 리터럴생성자 함수를 사용하는 방식이다.

각 방식의 특징과 장단점, 그리고 생성자 함수의 동작 방식에 대해 살펴보겠다.

 

 

1. 객체 리터럴 방식

객체 리터럴({ })은 객체를 생성할 때 가장 간단하고 직관적인 방법이다.

객체 리터럴을 사용하면 코드가 간결해지고, 객체를 정의하는 것이 쉬워진다.

const person1 = {
  name: "WI",
  getPersonName() {
    return `Hi, My Name is ${this.name}`;
  },
};

console.log(person1.getPersonName()); // "Hi, My Name is WI"

 

객체 리터럴로 생성한 객체는 하나의 객체만 생성된다.

동일한 구조를 가진 여러 객체를 생성하려면 매번 반복적으로 동일한 프로퍼티와 메서드를 작성해야 하므로

재사용성이 떨어지고 코드가 중복된다.

 


2. 생성자 함수 방식

생성자 함수는 new 연산자와 함께 호출하여 여러 객체를 생성할 수 있는 방법이다.

생성자 함수는 객체의 템플릿 역할을 하며, 동일한 구조를 가진 객체를 여러 개 만들 수 있게 도와준다.

// 생성자 함수 Person 선언
function Person(name) {
  this.name = name;
  this.getPersonName = function () {
    return `Hi, My Name is ${this.name}`;
  };
}

// new 연산자와 함께 Person 객체(인스턴스) 생성
const person1 = new Person("WI");
const person2 = new Person("YOUNGMIN");

console.log(person1.getPersonName()); // "Hi, My Name is WI"
console.log(person2.getPersonName()); // "Hi, My Name is YOUNGMIN"

 

생성자 함수를 사용하면 동일한 구조의 여러 객체를 쉽게 생성할 수 있다.

코드 중복을 줄이고, 객체 생성 시 필요한 데이터만 전달하면 되므로 효율적이다.


3. 생성자 함수의 동작 원리

생성자 함수는 new 연산자와 함께 호출될 때 특별한 동작을 한다. 이때 자바스크립트 엔진은 다음의 과정을 수행한다.

 

1. 빈 객체 생성 및 this 바인딩: new 연산자가 호출되면, 빈 객체가 생성되고 그 객체는 this에 바인딩된다.

function Person(name) {
  console.log(this); // 빈 객체가 바인딩된 Person{}
  this.name = name;
}

const person1 = new Person("WI");

 

2. 인스턴스 초기화: 생성자 함수 몸체 내에서 this에 프로퍼티와 메서드를 추가하고 초기화한다.

function Person(name) {
  this.name = name;
  this.getPersonName = function () {
    return `Hi, My Name is ${this.name}`;
  };
}

const person1 = new Person("WI");
console.log(person1.getPersonName()); // "Hi, My Name is WI"

 

3. 인스턴스 반환: 생성자 함수의 실행이 끝나면, this가 암묵적으로 반환된다. 이는 생성된 객체를 반환하는 과정이다.

function Person(name) {
  this.name = name;
}

const person = new Person("WI");
console.log(person); // Person { name: 'WI' }

4. new 연산자 없이 호출할 때

만약 생성자 함수를 new 없이 호출하면, 생성자 함수는 일반 함수처럼 동작하며 undefined를 반환한다.

function Person(name) {
  this.name = name;
}

const person1 = Person("WI"); // new 없이 호출
console.log(person1); // undefined

위 예제에서 this는 전역 객체(window)를 가리키게 되며, name 프로퍼티는 전역 객체에 추가된다.

이는 의도치 않은 부작용을 일으킬 수 있다.


5. new.target과 스코프 세이프 생성자 패턴

new.target은 ES6에서 도입된 문법이다.

이 문법을 사용하면, new 연산자와 함께 생성자 함수가 호출되었는지 확인할 수 있다.

new.target은 생성자 함수가 new 연산자 없이 호출될 때 undefined가 되고,

new 연산자와 함께 호출될 때는 생성자 함수 자신을 참조한다.

 

왜 필요한가?

일반적으로, 자바스크립트에서 생성자 함수는 new 연산자와 함께 호출되어야 올바르게 동작한다.

그런데 new 없이 생성자 함수를 호출할 때 의도하지 않은 문제가 발생할 수 있다.

예를 들어, 생성자 함수가 전역 객체에 값을 할당하거나, 반환 값이 잘못될 수 있다.

 

new.target을 사용하면 생성자 함수가 new 연산자 없이 호출된 경우를 감지해서

자동으로 new 연산자를 적용하거나, 에러를 던지는 방식으로 문제를 해결할 수 있다.

 

 

예시 1: new.target을 사용한 자동 new 처리

function Person(name) {
  if (!new.target) {
    // new 없이 호출되면, 자동으로 new 연산자를 적용
    return new Person(name); // 재귀적으로 호출하여 new가 적용되게 만듬
  }
  this.name = name;
  this.getPersonName = function() {
    return `Hi, My Name is ${this.name}`;
  };
}

// new 없이 호출
const person = Person("WI");
console.log(person.getPersonName()); // "Hi, My Name is WI"

new.target이 undefined면 new 연산자가 없다는 뜻이다.

이 경우, new Person(name)으로 재귀적으로 다시 new 연산자를 적용하여 생성자를 호출하게 만든다.

이 방법은 new 연산자가 없는 호출을 자동으로 처리하게 도와준다.

 

 

5.2 스코프 세이프 생성자 패턴

스코프 세이프 생성자 패턴은 new.target을 지원하지 않는 구형 브라우저에서

new 연산자 없이 호출된 생성자 함수가 제대로 동작하도록 보장하는 패턴이다.

 

이 패턴은 this instanceof Person을 이용하여, new 없이 생성자 함수가 호출되는 경우를 감지하고,

필요한 경우 new를 자동으로 적용한다.

 

예시 2: 스코프 세이프 생성자 패턴

function Person(name) {
  // Person 생성자 함수가 new 연산자와 함께 호출되지 않는 경우, this는 전역 객체 window 를 가리킨다.
  // 즉, this 는 Person 과 프로토타입에 의해 연결되지 않는다.
  if (!(this instanceof Person)) {
    // new 연산자와 함께 호출된 Person 인스턴스를 반환하도록 재귀호출 한다.
    return new Person(name);
  }

  this.name = name;
  this.getPersonName = function () {
    return `Hi, My Name is ${this.name}`;
  };
}

// new 연산자 없이 생성자 함수를 호출
const person = Person("WI");

// 그럼에도 불구하고, Person 인스턴스가 정상적으로 생성되었고, 내부 메서드 호출됨
console.log(person.getPersonName()); // Hi, My Name is WI
  • this instanceof Person은 this가 Person의 인스턴스인지 확인하는 구문이다.
  • 만약 new 없이 함수가 호출되면, this가 전역 객체를 가리키게 되고, 이 경우 this instanceof Person은 false가 된다.
  • 그럼 return new Person(name);가 실행되어 new 연산자가 적용되고, 정상적으로 객체가 생성된다.

 

스코프 세이프 생성자 패턴은 대부분의 빌트인 생성자 함수에 대해서도 적용되어, 

new 연산자와 함께 호출되었는지를 확인 후 적절한 값을 반환시킨다.

 

단, 원시타입의 빌트인 생성자 함수( Number, String, boolean ) 에 대해서는 이를 보장하지 않고, 원시 값을 반환하기도 한다.

const num = Number("123");
console.log(num, typeof num); // 123 number

const str = String(123);
console.log(str, typeof str); // 123 string

const bool = Boolean("true");
console.log(bool, typeof bool); // true boolean