내일배움캠프 TIL (230210): 자바스크립트 생성자 함수 / prototype 문법 / class 문법

Jiumn·2023년 2월 10일
0

자바스크립트 생성자 함수 vs. prototype 문법 vs. class 문법

nest.js 공부를 시작하려고 보니 class 문법에 대한 이해가 부족하다는 생각이 들었다.

class 문법 공부를 하려고 보니 자바스크립트에서 "'class는 prototype의 문법적 설탕(syntax sugar)'인가?"하는 말이 나왔다.
그럼 prototype과 class의 차이는 뭐지?
그러다가 생성자 함수를 통한 객체 생성과 리터럴 객체 생성과 차이는 뭐지?
라는 꼬꼬무에 정리 겸 간단하게 포스팅을 해보려고 한다.


생성자 함수

{}를 사용해서 직접 프로퍼티를 작성해주는 것이 객체 리터럴에 의한 객체 생성 방식이다.

객체 리터럴 방식의 문제점은 동일한 프로퍼티를 갖는 객체를 생성할 때 일일이 새로 만들어줘야 한다는 점이다.

그래서 등장한 것이 바로 생성자 함수다.
'생성자 함수'라는 이름 때문에 특별한 형태나 이름이 있을 것 같은데(class처럼 앞에 붙는다거나 하는), 사실 별 다를 게 없다.
객체 인스턴트를 생성하는 생성자라는 의미에서 생성자일 뿐 일반 함수와 형태가 같다.
다만 일반 함수와 구별을 위해 함수 이름의 첫 글자를 대문자로 써준다는 점이 좀 다르다. 이러한 명명법을 파스칼 케이스라고 한다.

(나는 한동안 생성자 함수가 contructor 라고 헷갈려 왔었다...( ◠‿ o̴̶̷̥᷅ ))

예를 들어 원의 속성을 가진 객체를 생성자 함수로 만들면 다음과 같다.

funtion Circle (radius) {
  this.radius = radius;
  this.getDiameter = function () {
    return 2 * this.radius;
  }
}

그런데 여기서 등장한 this가 또 머리를 아프게 한다.

모던 자바스크립트 딥다이브에 의하면
this는 '객체 자신의 프로퍼티나 메서드를 참조하기 위한 자기 참조 변수'다. this가 가리키는 값, (좀 더 어렵게 말하면) 즉 this 바인딩(binding)은 함수 호출 방식에 따라 동적으로 결정된다

  • 일반 함수에서 this: 전역 객체
  • 메서드로 호출 시 this: 메서드를 호출한 객체
  • 생성자 함수로서 호출 시 this: 생성자 함수가 미래에 생성할 인스턴스

여기서 바인딩(binding)은 식별자와 값을 연결하는 과정을 의미한다.

그럼 생성자 함수를 작성할 때 내부에서 어떤 일이 나타나는지 살펴보자.

function Circle(radius) {
  // 1. 암묵적으로 빈 객체가 생성되고 this가 바인딩된다.
  
  // 2. this가 바인딩되어 있는 인스턴스를 초기화한다. 
  this.radius = radius;
  this.getDiameter = function () {
    return 2 * this.radius;
  }
  // 3. 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환된다.
}

생성자 함수는 반드시 new 연산자와 함께 호출되어야 해당 객체의 인스턴스를 반환한다.


prototype 문법

생성자 함수에도 문제는 있다.

생성자 함수로 만든 객체의 인스턴스를 생성할 때는 동일한 메서드를 가진 인스턴스라도 중복적으로 생성해야 하기 때문이다.
이러한 중복은 메모리를 불필요하게 낭비하게 된다.

따라서 자바스크립트는 prototype 문법으로 상속을 구현한다.

위에서 예시를 든 원의 속성을 가진 객체를 prototype 문법으로 구현해보자.

function Circle(radius) {
	this.radius = radius;
}

Circle.prototype.getArea = function () {
	return Math.PI * this.radius ** 2;
}

생성자 함수로 생성된 Circle 함수는 radius라는 속성만 개별적으로 가지고 prototype 안에 getArea 라는 메서드를 가지게 된다. 따라서 Circle 의 모든 인스턴스는 prototype의 getArea 메서드를 상속 받게 된다.


class 문법

프로토타입 문법은 기존 객체지향 언어를 사용하는 프로그래머들에게 혼동을 줄 수 있어 class 문법이 추가되었다. (ES6)

객체의 인스턴스를 생성하는 방법이라는 점은 같지만 몇 가지 차이도 존재한다.

  • 생성자 함수는 new 연산자 없이 호출하면 일반함수로 호출된다. 하지만 class는 new 연산자 없이 호출하면 에러가 발생한다.
  • class에는 상속을 지원하는 exends, super 키워드가 있다.
  • class는 호이스팅이 발생하지 않는 것처럼 동작한다.
  • class 내의 코든 코드에는 암묵적으로 strict mode가 지정된다.
  • class의 constructor,프로토타입 메서드, 정적 메서드는 모두 프로퍼티 어튜리뷰트 [[Enumerable]]의 값이 false다. (열겨되지 않는다.)

그럼 클래스의 기본 형태를 알아보자.

class Person () {
	constructor(name) {
    // 1. 암묵적으로 인스턴스가 생성되고 this에 바인딩된다.
    
    // 2. this에 바인딩되어 있는 인스턴스를 초기화한다.
    this.name = name
    
    // 3. 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환된다.
  }
}

const person = new Person('jiumn')

console.log(person) // Person { name: 'jiumn' }
console.log(person.name) // jiumn

this가 바인딩되는 과정은 프로토타입과 비슷하나 클래스 내부를 초기화할 때는 constructor가 꼭 필요하다.

profile
Back-End Wep Developer. 꾸준함이 능력이다. Node.js, React.js를 주로 다룹니다.

0개의 댓글