[JS] new 없이 클래스 호출?

Chanki Hong·2022년 12월 15일
0

JavaScript

목록 보기
27/30
post-thumbnail

Array() 클래스를 이용한 코드를 보다가 문득 이상한 점을 발견했다.
클래스(객체 생성자 함수)를 클래스 호출(new 호출)이 아닌 일반 함수 호출(new 없이 호출)하는 것이었다.
JS의 클래스는 사실 함수이기 때문에 일반 함수로 호출은 가능하더라도 정상적으로 동작할 수 없는데 정상적으로 동작했다.
그러면 new 연산자(operator)가 꼭 필요한 건가?
또는 새로운 유형의 클래스인가?
숨겨진 내용이 있는 것 같아 Array()new 연산자(operator)에 대해 찾아보았다.


클래스를 new 없이 일반 함수 호출하면

class 로 선언한 클래스(객체 생성자 함수)

  • ES6 이후 부터 이용하는 class 문법에서는 TypeError 가 나와 진행 불가.
  • 또한
class Animal {
  constructor(type, name, sound) {
    this.type = type;
    this.name = name;
    this.sound = sound;
    this.say = () => console.log(this.sound);
  }
}
const pig = Animal('돼지', '꿀꿀이', '꿀꿀'); // TypeError: Class constructor Animal cannot be invoked without 'new'

function 으로 선언한 클래스(객체 생성자 함수)

  • 객체가 만들어 지지 않고 전역속성(전역변수, 전역함수)으로 만들어짐.
  • 즉, this 가 무시.
  • 인스턴스가 아니기 때문에 프로토타입도 사라짐.
function Animal(type, name, sound) {
  this.type = type;
  this.name = name;
  this.sound = sound;
  this.say = () => console.log(this.sound);
}
const pig = Animal('돼지', '꿀꿀이', '꿀꿀');
console.log(pig.type); // TypeError: Cannot read properties of undefined
console.log(pig.sound); // TypeError: Cannot read properties of undefined
console.log(type); // 돼지
console.log(sound); // 꿀꿀

new.target 프로퍼티

  • new.target 프로퍼티를 사용하면 클래스 호출인지 일반 함수 호출인지 구분.
  • new.target 은 일반 함수 호출 시 undefined 반환.
  • 클래스 호출(new 호출)은 클래스 자체 반환.
  • new.객체가 아니고 가상 문맥.
  • 모든 함수가 이용할 수 있는 메타 속성.
function Animal(type, name, sound) {
  console.log(new.target);
  this.type = type;
  this.name = name;
  this.sound = sound;
  this.say = () => console.log(this.sound);
}
const pig = Animal('돼지', '꿀꿀이', '꿀꿀'); // undefined
const dog = new Animal('강아지', '멍멍이', '멍멍'); // [Function: Animal]
  • class 문법에서도 동작.
class Animal {
  constructor(type, name, sound) {
    console.log(new.target);
    this.type = type;
    this.name = name;
    this.sound = sound;
    this.say = () => console.log(this.sound);
  }
}
const pig = new Animal('돼지', '꿀꿀이', '꿀꿀'); // [class Animal]

호출에 따라 동작을 다르게

  • ES6 class 문법에서는 이용 불가능.
  • 클래스를 클래스 호출과 일반 함수 호출시 다른 동작 하도록.
function Animal(type, name, sound) {
  if (!new.target) {
    return console.log(`${name}는(은) "${sound}" 소리를 내요.`);
  }
  this.type = type;
  this.name = name;
  this.sound = sound;
  this.say = () => console.log(this.sound);
}

const pigA = Animal('돼지', '꿀꿀이', '꿀꿀'); // 꿀꿀이는(은) "꿀꿀" 소리를 내요.
const pigB = new Animal('돼지', '꿀꿀이', '꿀꿀');
pigB.say(); // 꿀꿀

호출에 상관 없이 동작을 같게

  • ES6 class 문법에서는 이용 불가능.
  • 클래스를 클래스 호출과 일반 함수 호출과 관련없이 같은 동작 하도록.
  • 클래스가 어떤 경우에도 동일하게 동작.
function Animal(type, name, sound) {
  if (!new.target) {
    return new Animal(type, name, sound); // new가 없으면 return으로 붙여줌.
  }
  this.type = type;
  this.name = name;
  this.sound = sound;
  this.say = () => console.log(this.sound);
}
const pig = Animal('돼지', '꿀꿀이', '꿀꿀'); // new 없이 호출.

console.log(pig.type); // 돼지
console.log(pig.sound); // 꿀꿀

내장 클래스가 언제부터(ES5 이전과 ES6이후) 내장되었냐에 따라서;
즉, class 문법으로 정의 되었는지 function 문법으로 정의 되었는지에 따라 다른것 같다.
Array() 클래스는 function 으로 정의 되었고, new.target 프로퍼티로 클래스 호출과 일반 함수 호출 관련 없이 같은 동작을 하도록 설계 된 것이다.

const a = Array(5);
console.log(b.length); // 5
console.log(typeof b); // object

이러한 클래스가 몇 개 더 존재 하는데 Error(), Function() 등이 있다.
다만 new 를 이용하면 누구나 클래스와 인스턴스 생성임을 알 수 있고, 모든 클래스에 일관적으로(모든 클래스가 어떻게 동작하는지 알지 못하기) 쓸수있기 때문에 new 이용을 지향해야 하고, ES6class 문법의 의도(if(!new.target) 제한) 또한 동일하다고 생각한다.


0개의 댓글