생성자 함수와 class의 차이

IT공부중·2021년 2월 11일
4

JavsScript

목록 보기
17/22

자바스크립트에서 객체를 만들기 위한 템플릿으로 생성자 함수와 class를 사용한다. class는 생성자 함수에서 사용하기만 편하게 한 편의적 문법(syntactic sugar)라고 하는 사람들이 많다. 하지만 동일한 역할을 하는 것 외에도 추가적인 기능들이 있다.

  1. class 생성자는 new와 함께 호출하지 않으면 에러가 발생한다. class로 만든 함수엔 특수내부 프로퍼티인 [[FunctionKind]]: 'classConstructor' 가 붙는다. 그래서 class를 사용하면 해당 프로퍼티를 확인하는 과정이 있기 때문에 new를 꼭 붙여야만 한다.
class User {
  constructor() {}
}

alert(typeof User); // function
User(); // TypeError: Class constructor User cannot be invoked without 'new'
  1. 클래스의 메서드는 열거할 수 없다. (non-enumerable). 클래스의 prototype 프로퍼티에 추가된 메서드 전체의 enumerable 플래그는 false이기 때문이다. 즉, for..in으로 객체를 순회할 때, 메서드가 대상에서 제외된다.

  2. 클래스는 항상 엄격모드로 실행된다.(use strict) 클래스 생성자 안 코드 전체에는 자동으로 엄격모드가 적용된다.

그럼 생성자 함수에서도 이와 비슷하게 작동하게 만들 순 없을까? 한번 해보았다.

생성자 함수에서도 클래스와 비슷하게 만들어보기

new를 붙이지 않았을 경우 에러 내기

첫번재로는 new로 호출되지 않았을 경우 에러를 나게 만들어 볼 것이다. 다음과 같은 코드를 사용하면 new를 사용했는지 아닌지를 확인할 수 있다.

function Test(name) {
  if (!new.target) return new Error('new를 붙여서 사용해주세요.');

  this.name = name;
}

const person = Test('이름');
console.log(person);

다음과 같이 에러가 나타나는 것을 확인할 수 있다. new.target은 new를 쓸 경우 생성자 함수를 가리킨다. 그렇지 않을 경우에는 undefined가 된다.

use strict 적용하기

'use strict' 관련은 그냥 함수 안에 'use strict' 를 사용해주면 될 것이다.

function Test(name) {
  'use strict';
  if (!new.target) return new Error('new를 붙여서 사용해주세요.');

  this.name = name;
  this.sayHello = function (hey, hey) {
    console.log(hey);
  };
}

const person = new Test('이름');
console.log(person);

그러면 중복된 parameter 등을 썼을 때 에러가 나는 것을 확인할 수 있다.

prototype 메소드의 enumerable을 false로 만들기

또한 이제 prototype의 메소드들을 순회할 수 없게 만들어야한다. 나는 이런식으로 코드를 짜보았다.

function Test(name) {
  'use strict';
  if (!new.target) return new Error('new를 붙여서 사용해주세요.');
  this.name = name;
}

Test.prototype.sayHello = function () {
  console.log('hello');
};

function convertMethodNonEnumerable(target) {
  for (let property in target) {
    if (
      !target.hasOwnProperty(property) ||
      typeof target[property] !== 'function'
    )
      continue;

    Object.defineProperty(target, property, {
      value: target[property],
      enumerable: false,
      writable: true,
      configurable: true,
    });
  }
}

const person = new Test('이름');
console.log('----- 기본 -----');
for (let k in person) {
  console.log(k);
}

convertMethodNonEnumerable(Test);
console.log('----- 적용 후 -----');
for (let k in person) {
  console.log(k);
}

console.log('실행 확인');
person.sayHello();

이렇게 코드를 실행 시키고 나면 처음에는 person의 속성으로 name과 sayHello가 둘 다 나타나지만, 함수를 적용 시키고 나면은 prototype에 있던 method는 나열이 되지 않는 것을 확인할 수 있다.

이러한 사항들을 추가해놓은게 class이다.
클래스로는 훨씬 짧게 작성할 수 있다.

class Test {
  constructor(name) {
    this.name = name;
  }
  sayHello() {
    console.log('hello');
  }
}

const person = new Test('이름');

for (let property in person) {
  console.log(property);
}

결과로 메소드는 출력되지 않고, 일반 속성만 출력되는 것을 확인할 수 있었다.

profile
4년차 프론트엔드 개발자 문건우입니다.

0개의 댓글