[πŸ“– λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ λ”₯λ‹€μ΄λΈŒ] 25μž₯. 클래슀

λ…Έμ˜μ™„Β·2023λ…„ 12μ›” 27일
0

JavaScript(Deep Dive)

λͺ©λ‘ 보기
20/23
post-thumbnail
post-custom-banner

클래슀

1. ν΄λž˜μŠ€λŠ” ν”„λ‘œν† νƒ€μž…μ˜ 문법적 섀탕인가?

μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” ν΄λž˜μŠ€κ°€ ν•„μš”κ°€ μ—†λŠ” ν”„λ‘œν† νƒ€μž… 기반 객체지ν–₯ ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄λ‹€. ES5μ—μ„œλŠ” 클래슀 없이도 μƒμ„±μž ν•¨μˆ˜μ™€ ν”„λ‘œν† νƒ€μž…μ„ 톡해 객체지ν–₯ μ–Έμ–΄μ˜ 상속을 κ΅¬ν˜„ν•  수 μžˆλ‹€.

// ES5 μƒμ„±μž ν•¨μˆ˜
var Person = (function () {
  // μƒμ„±μž ν•¨μˆ˜
  function Person(name) {
    this.name = name;
  }
  
  // ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ
  Person.prototype.sayHi = function () {
    console.log(`Hi! My name is ` + this.name);
  };
  
  // μƒμ„±μž ν•¨μˆ˜ λ°˜ν™˜
  return Person;
}());

// μΈμŠ€ν„΄μŠ€ 생성
var me = new Person('Lee');
me.sayHi(); // Hi! My name is Lee

ES6의 ν΄λž˜μŠ€κ°€ 기쑴의 ν”„λ‘œν† νƒ€μ΄ 기반 객체지ν–₯ λͺ¨λΈμ„ νμ§€ν•˜κ³  μƒˆλ‘­κ²Œ 클래슀 기반 객체지ν–₯ λͺ¨λΈμ„ μ œκ³΅ν•˜λŠ” 것은 μ•„λ‹ˆλ‹€. 사싀 ν΄λž˜μŠ€λŠ” ν•¨μˆ˜μ΄λ©° κΈ°μ‘΄ ν”„λ‘œν† νƒ€μž… 기반 νŒ¨ν„΄μ„ 클래슀 기반 νŒ¨ν„΄μ²˜λŸΌ μ‚¬μš©ν•  수 μžˆλ„λ‘ ν•˜λŠ” 문법적 섀탕이라고 λ³Ό 수 μžˆλ‹€.

단, ν΄λž˜μŠ€μ™€ μƒμ„±μž ν•¨μˆ˜λŠ” λͺ¨λ‘ ν”„λ‘œν† νƒ€μž… 기반의 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜μ§€λ§Œ μ •ν™•νžˆ λ™μΌν•˜κ²Œ λ™μž‘ν•˜μ§€λŠ” μ•ŠλŠ”λ‹€. ν΄λž˜μŠ€λŠ” μƒμ„±μž ν•¨μˆ˜λ³΄λ‹€ μ—„κ²©ν•˜λ©° μƒμ„±μž ν•¨μˆ˜μ—μ„œλŠ” μ œκ³΅ν•˜μ§€ μ•ŠλŠ” κΈ°λŠ₯도 μ œκ³΅ν•œλ‹€.

βœ“ 클래슀λ₯Ό newμ—°μ‚°μž 없이 ν˜ΈμΆœν•˜λ©΄ μ—λŸ¬κ°€ λ°œμƒν•œλ‹€. ν•˜μ§€λ§Œ μƒμ„±μž ν•¨μˆ˜λ₯Ό new μ—°μ‚°μž 없이 ν˜ΈμΆœν•˜λ©΄ 일반 ν•¨μˆ˜λ‘œμ„œ ν˜ΈμΆœλœλ‹€.

βœ“ ν΄λž˜μŠ€λŠ” 상속을 μ§€μ›ν•˜λŠ” extends와 superν‚€μ›Œλ“œλ₯Ό μ œκ³΅ν•œλ‹€. ν•˜μ§€λ§Œ μƒμ„±μž ν•¨μˆ˜λŠ” extends와 superν‚€μ›Œλ“œλ₯Ό μ§€μ›ν•˜μ§€ μ•ŠλŠ”λ‹€.

βœ“ ν΄λž˜μŠ€λŠ” ν˜Έμ΄μŠ€νŒ…μ΄ λ°œμƒν•˜μ§€ μ•ŠλŠ” κ²ƒμ²˜λŸΌ λ™μž‘ν•œλ‹€ ν•˜μ§€λ§Œ ν•¨μˆ˜ μ„ μ–Έλ¬ΈμœΌλ‘œ μ •μ˜λœ μƒμ„±μž ν•¨μˆ˜λŠ” ν•¨μˆ˜ ν˜Έμ΄μŠ€νŒ…μ΄, ν•¨μˆ˜ ν‘œν˜„μ‹μœΌλ‘œ μ •μ˜ν•œ μƒμ„±μž ν•¨μˆ˜λŠ” λ³€μˆ˜ ν˜Έμ΄μŠ€νŒ…μ΄ λ°œμƒν•œλ‹€

βœ“ ν΄λž˜μŠ€λ‚΄μ˜ λͺ¨λ“  μ½”λ“œμ—λŠ” μ•”λ¬΅μ μœΌλ‘œ strict modeκ°€ μ§€μ •λ˜μ–΄ μ‹€ν–‰λ˜λ©° strict modeλ₯Ό ν•΄μ œν•  수 μ—†λ‹€. ν•˜μ§€λ§Œ μƒμ„±μž ν•¨μˆ˜κ°€ μ§€μ •λ˜μ§€ μ•ŠλŠ”λ‹€.

βœ“ 클래슀의 constructor ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ 정적 λ©”μ„œλ“œλŠ” λͺ¨λ‘ ν”„λ‘œνΌν‹° μ–΄νŠΈλ¦¬λ·°νŠΈ [[Enuerable]]의 값이 falseλ‹€. λ‹€μ‹œ 말헀, μ—΄κ±°λ˜μ§€ μ•ŠλŠ”λ‹€.

μƒμ„±μž ν•¨μˆ˜ ν΄λž˜μŠ€λŠ” ν”„λ‘œν† νƒ€μž… 기반의 객체지ν–₯을 κ΅¬ν˜„ν–ˆλ‹€λŠ” μ μ—μ„œ 맀우 μœ μ‚¬ν•˜μ§€λ§Œ, ν΄λž˜μŠ€λŠ” κ²¬κ³ ν•˜κ³  λͺ…λ£Œν•˜λ©° extends와 super ν‚€μ›Œλ“œλŠ” 상속 관계 κ΅¬ν˜„μ„ λ”μš± κ°„κ²°ν•˜κ³  λͺ…λ£Œν•˜κ²Œ ν•œλ‹€. λ”°λΌμ„œ ν΄λž˜μŠ€λŠ” μƒˆλ‘œμš΄ 객체 생성 λ§€μ»€λ‹ˆμ¦˜μœΌλ‘œ λ³΄λŠ” 것이 μ’€ 더 ν•©λ‹Ήν•˜λ‹€.

2. 클래슀 μ •μ˜

ν΄λž˜μŠ€λŠ” class ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ •μ˜ 클래슀 이름은 μƒμ„±μž ν•¨μˆ˜μ™€ λ§ˆμ°¬κ°€μ§€λ‘œ 파슀칼 μΌ€μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜λŠ” 것이 일반적. μ‚¬μš©ν•˜μ§€ μ•Šμ•„λ„ μ—λŸ¬κ°€ λ°œμƒν•˜μ§€λŠ” μ•ŠμŒ.

// 클래슀 μ„ μ–Έλ¬Έ
Class Person {}

μΌλ°˜μ μ΄μ§€λŠ” μ•Šμ§€λ§Œ ν•¨μˆ˜μ™€ λ§ˆμΉœκ°€μ§€λ‘œ ν‘œν˜„μ‹μœΌλ‘œ 클래슀λ₯Ό μ •μ˜ν•  μˆ˜λ„ μžˆλ‹€. μ΄λ•Œ ν΄λž˜μŠ€λŠ” ν•¨μˆ˜μ™€ λ§ˆμ°¬κ°€μ§€λ‘œ 이름을 κ°€μ§ˆ μˆ˜λ„ 있고, 갖지 μ•Šμ„ μˆ˜λ„ μžˆλ‹€.

// 읡λͺ… 클래슀 ν‘œν˜„μ‹
const Person = class {};

// κΈ°λͺ… 클래슀 ν‘œν˜„μ‹
cosnt Person = class MyClass{};

클래슀λ₯Ό ν‘œν˜„μ‹μœΌλ‘œ μ •μ˜ν•  수 μžˆλ‹€λŠ” 것은 ν΄λž˜μŠ€κ°€ κ°’μœΌλ‘œ μ‚¬μš©ν•  수 μžˆλŠ” 일급 κ°μ²΄λΌλŠ” 것을 μ˜λ―Έν•œλ‹€.

βœ“ 무λͺ…μ˜ λ¦¬ν„°λŸ΄λ‘œ 생성할 수 μžˆλ‹€. 즉, λŸ°νƒ€μž„μ— 생성이 κ°€λŠ₯ν•˜λ‹€.
βœ“ λ³€μˆ˜λ‚˜ 자료ꡬ쑰(객체, λ°°μ—΄ λ“±)에 μ €μž₯ν•  수 μžˆλ‹€.
βœ“ ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜μ—κ²Œ 전달할 수 μžˆλ‹€.
βœ“ ν•¨μˆ˜μ˜ λ°˜ν™˜κ°’μœΌλ‘œ μ‚¬μš©ν•  수 μžˆλ‹€.

μ’€ 더 μžμ„Ένžˆ λ§ν•˜μžλ©΄ ν΄λž˜μŠ€λŠ” ν•¨μˆ˜μ΄λ©° κ°’μ²˜λŸΌ μ‚¬μš©ν•  수 μžˆλŠ” 일급 객체닀.

클래슀 λͺΈμ²΄μ—λŠ” 0개 μ΄μƒμ˜ λ©”μ„œλ“œλ§Œ μ •μ˜ν•  수 있으며 클래슀 λͺΈμ²΄μ—μ„œ μ •μ˜ν•  수 μžˆλŠ” λ©”μ„œλ“œλŠ” constructor(μƒμ„±μž) ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ 정적 λ©”μ„œλ“œ μ„Έ 가지가 μžˆλ‹€.

// 클래슀 μ„ μ–Έλ¬Έ
Class Person {
  // μƒμ„±μž
  constructor(name) {
    // μΈμŠ€ν„΄μŠ€ 생성 및 μ΄ˆκΈ°ν™”
    this.name = name; // name ν”„λ‘œνΌν‹°λŠ” publicν•˜λ‹€.
  }
  
  // ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ
  sayHi() {
    console.log(`Hi! My name is ${this.name}`);
  }
  
  // 정적 λ©”μ„œλ“œ
  static sayHello() {
    console.log('Hello!');
  }
}

// μΈμŠ€ν„΄μŠ€ 생성
const me = new Person ('Noh');

// μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œνΌν‹° μ°Έμ‘°
console.log(me.name); // Noh
// ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ 호좜
me.sayHi(); // Hi! My name is Noh
// 정적 λ©”μ„œλ“œ 호좜
Person.sayHello(); // Hello!

3. 클래슀 ν˜Έμ΄μŠ€νŒ…

// ν΄λž˜μŠ€λŠ” ν•¨μˆ˜λ‘œ 평가.
class Person {}

console.log(typeof Person); // function

ν΄λž˜μŠ€λŠ” 클래슀 μ •μ˜ 이전에 μ°Έμ‘°ν•  수 μ—†λ‹€.

console.log(Person);
 // ReferenceError: Cannot access 'Person' before initialization

// 클래슀 μ„ μ–Έλ¬Έ
class Person {}

클래슀 선언문은 마치 ν˜Έμ΄μŠ€νŒ…μ΄ λ°œμƒν•˜μ§€ μ•ŠλŠ” κ²ƒμ²˜λŸΌ λ³΄μ΄λ‚˜ 그렇지 μ•Šλ‹€.

const Person = '';

{
  // ν˜Έμ΄μŠ€νŒ…μ΄ λ°œμƒν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ ''이 좜λ ₯λ˜μ–΄μ•Ό ν•œλ‹€.
  // ν•˜μ§€λ§Œ class Person이 ν˜Έμ΄μŠ€νŒ…μ΄ λ°œμƒν•΄ ReferenceError
  
  // 클래슀 μ„ μ–Έλ¬Έ
  class Person {}
}

클래슀 선언문도 λ³€μˆ˜ μ„ μ–Έ ν•¨μˆ˜ μ •μ˜μ™€ λ§ˆμ°¬κ°€μ§€λ‘œ ν˜Έμ΄μŠ€νŒ…μ΄ λ°œμƒν•œλ‹€. 단, ν΄λž˜μŠ€λŠ” let const ν‚€μ›Œλ“œλ‘œ μ„ μ–Έν•œ λ³€μˆ˜μ²˜λŸΌ ν˜Έμ΄μŠ€νŒ…λœλ‹€.

λ”°λΌμ„œ ν΄λž˜μŠ€λŠ” μ„ μ–Έλ¬Έ 이전에 μΌμ‹œμ  μ‚¬κ°μ§€λŒ€(TDZ)에 빠지기 λ•Œλ¬Έμ— ν˜Έμ΄μŠ€νŒ…μ΄ λ°œμƒν•˜μ§€ μ•ŠλŠ”κ²ƒμ²˜λŸΌ λ™μž‘ν•œλ‹€. λͺ¨λ“  선언문은 λŸ°νƒ€μž„ 이전 μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진에 μ˜ν•΄ λ¨Όμ € μ‹€ν–‰λœλ‹€.

4. μΈμŠ€ν„΄μŠ€ 생성

ν΄λž˜μŠ€λŠ” μƒμ„±μž ν•¨μˆ˜μ΄λ©° new μ—°μ‚°μžμ™€ ν•¨κ»˜ ν˜ΈμΆœλ˜μ–΄ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•œλ‹€.

class Person {}

// μΈμŠ€ν„΄μŠ€ 생성
const me = new Person();
console.log(me); // Person{}

ν΄λž˜μŠ€λŠ” μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λŠ” 것이 μœ μΌν•œ 쑴재 μ΄μœ μ΄λ―€λ‘œ λ°˜λ“œμ‹œ new μ—°μ‚°μžμ™€ ν•¨κ»˜ ν˜ΈμΆœν•΄μ•Ό ν•œλ‹€.

class Person {}

// 클래슀λ₯Ό new μ—°μ‚°μž 없이 ν˜ΈμΆœν•˜λ©΄ νƒ€μž… μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.
const me = Person();
// TypeError: Class constructor Foo cannot be invoked without 'new'

클래슀 ν‘œν˜„μ‹μœΌλ‘œ μ •μ˜λœ 클래슀의 경우 클래슀λ₯Ό κ°€λ¦¬ν‚€λŠ” μ‹λ³„μž(Person)λ₯Ό μ‚¬μš©ν•΄ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜μ§€ μ•Šκ³  κΈ°λͺ… 클래슀 ν‘œν˜„μ‹μ˜ 클래슀 이름(MyClass)을 μ‚¬μš©ν•΄ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λ©΄ μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.

const Person = class MyClass {};

// ν•¨μˆ˜ ν‘œν˜„μ‹κ³Ό λ§ˆμ°¬κ°€μ§€λ‘œ 클래슀λ₯Ό κ°€λ¦¬ν‚€λŠ” μ‹λ³„μžλ‘œ μΈμŠ€ν„΄μŠ€λ₯Ό 생성해야 ν•œλ‹€.
const me = new Person();

// 클래슀 이름 MyClassλŠ” ν•¨μˆ˜μ™€ λ™μΌν•˜κ²Œ 클래슀 λͺΈμ²΄ λ‚΄λΆ€μ—μ„œλ§Œ μœ νš¨ν•œ μ‹λ³„μžλ‹€.
console.log(MyClass); // ReferenceError: MyClass is not defined

const you = new MyClass(); // ReferenceError: MyClass is not defined

5. λ©”μ„œλ“œ

클래슀 λͺΈμ²΄μ—λŠ” 0개 μ΄μƒμ˜ λ©”μ„œλ“œλ§Œ μ„ μ–Έν•  수 μžˆλ‹€. 클래슀 λͺΈμ²΄μ—μ„œ μ •μ˜ν•  수 μžˆλŠ” λ©”μ„œλ“œλŠ” constructor(μƒμ„±μž) ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ 정적 λ©”μ„œλ“œ μ„Έ 가지가 μžˆλ‹€.

πŸ’‘ 클래슀 μ •μ˜μ— λŒ€ν•œ μƒˆλ‘œμš΄ μ œμ•ˆ 사양

  • ECMAScript 사양에 λ”°λ₯΄λ©΄ μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°λŠ” λ°˜λ“œμ‹œ constructorλ‚΄λΆ€μ—μ„œ μ •μ˜ν•΄μ•Ό ν•œλ‹€.
  • ν•˜μ§€λ§Œ 클래슀 λͺΈμ²΄μ— λ©”μ„œλ“œλΏλ§Œμ΄ μ•„λ‹ˆλΌ ν”„λ‘œνΌν‹°λ„ μ •μ˜ν•  수 있게 μƒˆλ‘œμš΄ ν‘œμ€€ 사양이 μ œμ•ˆλ˜μ–΄ μžˆλ‹€.
  • μ΅œμ‹  λͺ¨λ˜ λΈŒλΌμš°μ €μ—λŠ” 이미 λ°˜μ˜λ˜μ–΄ μ‚¬μš©μ΄ κ°€λŠ₯ν•˜λ‹€.

5-1. constructor

  • constructorλŠ” μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜κ³  μ΄ˆκΈ°ν™”ν•˜κΈ° μœ„ν•œ 특수 λ©”μ„œλ“œλ‹€.
  • constructorλŠ” 이름을 λ³€κ²½ν•  수 μ—†λ‹€.
class Person {
  // μƒμ„±μž
  constructor(name) {
    // μΈμŠ€ν„΄μŠ€ 생성 및 μ΄ˆκΈ°ν™”
    this.name = name;
  }
}
// 클래슀
class Person {
  // μƒμ„±μž
  constructor(name) {
    // μΈμŠ€ν„΄μŠ€ 생성 및 μ΄ˆκΈ°ν™”
    this.name = name;
  }
}

// μƒμ„±μž ν•¨μˆ˜
function Person(name) {
  // μΈμŠ€ν„΄μŠ€ 생성 및 μ΄ˆκΈ°ν™”
  this.name = name;
}

1️⃣ constructor λ‚΄λΆ€μ—μ„œ this에 μΆ”κ°€ν•œ ν”„λ‘œνΌν‹°λŠ” μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°κ°€ λœλ‹€.

2️⃣ constructor λ‚΄λΆ€μ˜ thisλŠ” μƒμ„±μž ν•¨μˆ˜μ™€ λ§ˆμ°¬κ°€μ§€λ‘œ ν΄λž˜μŠ€κ°€ μƒμ„±ν•œ μΈμŠ€ν„΄μŠ€λ₯Ό 가리킨닀.

3️⃣ ν΄λž˜μŠ€κ°€ μƒμ„±ν•œ μΈμŠ€ν„΄μŠ€λ‚˜ ν΄λž˜μŠ€κ°€ ν‰κ°€λ˜μ–΄ μƒμ„±λœ ν•¨μˆ˜ 객체 어디에도 constructor λ©”μ„œλ“œκ°€ 보이지 μ•ŠλŠ”λ‹€λŠ” 것. μ΄λŠ” 클래슀 λͺΈμ²΄μ— μ •μ˜ν•œ constructorκ°€ λ‹¨μˆœν•œ λ©”μ„œλ“œκ°€ μ•„λ‹ˆλΌλŠ” 것을 의미.

constructorλŠ” λ©”μ„œλ“œλ‘œ ν•΄μ„λ˜λŠ” 것이 μ•„λ‹ˆλΌ ν΄λž˜μŠ€κ°€ ν‰κ°€λ˜μ–΄ μƒμ„±ν•œ ν•¨μˆ˜ 객체 μ½”λ“œμ˜ 일뢀가 λœλ‹€.

4️⃣ constructorλŠ” 클래슀 내에 μ΅œλŒ€ ν•œ 개만 μ‘΄μž¬ν•  수 μžˆλ‹€. λ§Œμ•½ ν΄λž˜μŠ€κ°€ 2개 μ΄μƒμ˜ constructorλ₯Ό ν¬ν•¨ν•˜λ©΄ SyntaxErrorκ°€ λ°œμƒν•œλ‹€.

5️⃣ constructorλŠ” μƒλž΅ν•  수 μžˆλ‹€.

6️⃣ constructorλ₯Ό μƒλž΅ν•˜λ©΄ ν΄λž˜μŠ€μ— λ‹€μŒκ³Ό 같이 빈 constructorκ°€ μ•”λ¬΅μ μœΌλ‘œ μ •μ˜λœλ‹€.

7️⃣ constructorλ₯Ό μƒλž΅ν•œ ν΄λž˜μŠ€λŠ” 빈 constructor에 μ˜ν•΄ 빈 객체λ₯Ό μƒμ„±ν•œλ‹€.

8️⃣ μΈμŠ€ν„΄μŠ€ 생성할 λ•Œ 클래슀 μ™ΈλΆ€μ—μ„œ μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°μ˜ μ΄ˆκΈ°κ°’μ„ μ „λ‹¬ν•˜λ €λ©΄ constructor에 λ§€κ°œλ³€μˆ˜λ₯Ό μ„ μ–Έν•˜κ³  μΈμŠ€ν„΄μŠ€λ₯Ό 생성할 λ•Œ 초기 값을 μ „λ‹¬ν•œλ‹€.

class Person {
  constructor(name, address) {
    // 인수둜 μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™”
    this.name = name;
    this.address = address;
  }
}

// 인수둜 μ΄ˆκΈ°κ°’μ„ μ „λ‹¬ν•œλ‹€. μ΄ˆκΈ°κ°’μ€ constructor에 μ „λ‹¬λœλ‹€.
const me = new Person('Lee', 'Seoul');
console.log(me);

9️⃣ constructorλŠ” λ³„λ„μ˜ λ°˜ν™˜λ¬Έ(return)을 갖지 μ•Šμ•„μ•Ό ν•œλ‹€. ν•˜μ§€λ§Œ λͺ…μ‹œμ μœΌλ‘œ μ›μ‹œκ°’μ„ λ°˜ν™˜ν•˜λ©΄ μ›μ‹œκ°’ λ°˜ν˜Έλ‚˜μ€ λ¬΄μ‹œλœκ³  μ•”λ¬΅μ μœΌλ‘œ thisκ°€ λ°˜ν™˜λœλ‹€.

πŸ’‘ 클래슀의 constructor λ©”μ„œλ“œμ™€ ν”„λ‘œν† νƒ€μž…μ˜ construcotor ν”„λ‘œνΌν‹°

클래슀의 constructor λ©”μ„œλ“œμ™€ ν”„λ‘œν† νƒ€μž…μ˜ constructor ν”„λ‘œνΌν‹°λŠ” 이름이 κ°™μ•„ ν˜Όλ™ν•˜κΈ° μ‰½μ§€λ§Œ 직접적인 관련이 μ—†λ‹€. ν”„λ‘œν† νƒ€μž…μ˜ constructor ν”„λ‘œνΌν‹°λŠ” λͺ¨λ“  ν”„λ‘œν† νƒ€μž…μ΄ 가지고 μžˆλŠ” ν”„λ‘œνΌν‹°μ΄λ©°, μƒμ„±μž ν•¨μˆ˜λ₯Ό 가리킨닀.

5-2. ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ

βœ“ μƒμ„±μž ν•¨μˆ˜μ—μ„œ ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ 생성

// μƒμ„±μž ν•¨μˆ˜
function Person(name) {
  this.name = name;
}

// ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ
Person.prototype.sayHi = function () {
  console.log(`Hi! My name is ${this.name}`);
};

const me = new Person('Lee');
me.sayHi(); // Hi! My name is Lee

βœ“ ν΄λž˜μŠ€μ—μ„œ ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ 생성.

class Person {
  // μƒμ„±μž
  constructor(name) {
    // μΈμŠ€ν„΄μŠ€ 생성 및 μ΄ˆκΈ°ν™”
    this.name = name;
  }

  // ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ
  sayHi() {
    console.log(`Hi! My name is ${this.name}`);
  }
}

const me = new Person('Lee');
me.sayHi(); // Hi! My name is Lee

μƒμ„±μž ν•¨μˆ˜μ™€ λ§ˆμ°¬κ°€μ§€λ‘œ ν΄λž˜μŠ€κ°€ μƒμ„±ν•œ μΈμŠ€ν„΄μŠ€λŠ” ν”„λ‘œν† νƒ€μž… 체인의 일원이 λœλ‹€.

// me 객체의 ν”„λ‘œν† νƒ€μž…μ€ Person.prototypedlek.
Object.getProtype(me) === Person.prototype; // true
me instanceof Person; // true

// Person.prototype의 ν”„λ‘œν† νƒ€μž…μ€ Object.prototypedlek.
Object.getProtypeOf(Person.prototype) === Object.prototype; // true
me instanceof Object // true

// me 객체의 constructorλŠ” Person ν΄λž˜μŠ€λ‹€.
me.construcotr === Person // true

5-3. 정적 λ©”μ†Œλ“œ

정적 λ©”μ†Œλ“œλŠ” μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜μ§€ μ•Šμ•„λ„ ν˜ΈμΆœν•  수 μžˆλŠ” λ©”μ„œλ“œλ₯Ό λ§ν•œλ‹€.

μƒμ„±μž ν•¨μˆ˜ 정적 λ©”μ†Œλ“œ

// μƒμ„±μž ν•¨μˆ˜
function Person(name) {
  this.name = name;
}

// 정적 λ©”μ„œλ“œ
Person.sayHi = function () {
  console.log('Hi!');
};

// 정적 λ©”μ„œλ“œ 호좜
Person.sayHi(); // Hi!

ν΄λž˜μŠ€μ—μ„œλŠ” λ©”μ„œλ“œμ— static ν‚€μ›Œλ“œλ₯Ό 뢙이면 정적 λ©”μ„œλ“œ(클래슀 λ©”μ„œλ“œ)κ°€ λœλ‹€.

class Person {
  // μƒμ„±μž
  constructor(name) {
    // μΈμŠ€ν„΄μŠ€ 생성 및 μ΄ˆκΈ°ν™”
    this.name = name;
  }

  // 정적 λ©”μ„œλ“œ
  static sayHi() {
    console.log('Hi!');
  }
}

1️⃣ 정적 λ©”μ„œλ“œλŠ” ν΄λž˜μŠ€μ— λ°”μΈλ”©λœ λ©”μ„œλ“œκ°€ 되며, ν΄λž˜μŠ€λŠ” ν•¨μˆ˜ 객체둜 ν‰κ°€λ˜λ―€λ‘œ μžμ‹ μ˜ ν”„λ‘œνΌν‹° / λ©”μ„œλ“œλ₯Ό μ†Œμœ ν•  수 μžˆλ‹€.

2️⃣ ν΄λž˜μŠ€λŠ” 클래슀 μ •μ˜κ°€ 평가 λ˜λŠ” μ‹œμ μ— ν•¨μˆ˜ 객체가 λ˜λ―€λ‘œ μΈμŠ€ν„΄μŠ€μ™€ 달리 별닀λ₯Έ 생성 과정이 ν•„μš” μ—†λ‹€. λ”°λΌμ„œ 정적 λ©”μ„œλ“œλŠ” 클래슀 μ •μ˜ 이후 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜μ§€ μ•Šμ•„λ„ ν˜ΈμΆœν•  수 μžˆλ‹€.

3️⃣ 정적 λ©”μ„œλ“œλŠ” μΈμŠ€ν„΄μŠ€λ‘œ ν˜ΈμΆœν•  수 μ—†λ‹€. 정적 λ©”μ„œλ“œκ°€ λ°”μΈλ”©λœ 클래슀 μƒμ„±μž ν•¨μˆ˜μ—μ„œλŠ” μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œν† νƒ€μž… 체인상에 μ‘΄μž¬ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έ.

5-4. 정적 λ©”μ„œλ“œμ™€ ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œμ˜ 차이

1️⃣ 정적 λ©”μ„œλ“œμ™€ ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œλŠ” μžμ‹ μ΄ 속해 μžˆλŠ” ν”„λ‘œν†  νƒ€μž… 체인이 λ‹€λ₯΄λ‹€.

2️⃣ 정적 λ©”μ„œλ“œλŠ” 클래슀둜 ν˜ΈμΆœν•˜κ³  ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œλŠ” μΈμŠ€ν„΄μŠ€λ‘œ ν˜ΈμΆœν•œλ‹€.

3️⃣ 정적 λ©”μ„œλ“œλŠ” μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°λ₯Ό μ°Έμ‘°ν•  수 μ—†μ§€λ§Œ ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œλŠ” μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°λ₯Ό μ°Έμ‘°ν•  수 μžˆλ‹€.

정적 λ©”μ†Œλ“œ 예제

class Square {
  // 정적 λ©”μ„œλ“œ
  static area(width, height) {
    return width * height;
  }
}

console.log(Square.area(10, 10)); // 100

ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ 예제

class Square {
  constructor(width, height) {
    this.width = width;
    this.height = height;
  }

  // ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ
  area() {
    return this.width * this.height;
  }
}

const square = new Square(10, 10);
console.log(square.area()); // 100

πŸ’‘ ν‘œμ€€ 빌트인 객체의 정적 λ©”μ†Œλ“œ

// ν‘œμ€€ 빌트인 객체의 정적 λ©”μ†Œλ“œ
Math.max(1, 2, 3);          // -> 3
Number.isNaN(NaN);          // -> true
JSON.stringify({ a: 1 });   // -> "{"a":1}"
Object.is({}, {});          // -> false
Reflect.has({ a: 1 }, 'a'); // -> true

5-5. ν΄λž˜μŠ€μ—μ„œ μ •μ˜ν•œ λ©”μ„œλ“œμ˜ νŠΉμ§•

1️⃣ function ν‚€μ›Œλ“œλ₯Ό μƒλž΅ν•œ λ©”μ„œλ“œ μΆ•μ•½ ν‘œν˜„μ„ μ‚¬μš©ν•œλ‹€.

2️⃣ 객체 λ¦¬ν„°λŸ΄κ³ΌλŠ” λ‹€λ₯΄κ²Œ ν΄λž˜μŠ€μ— λ©”μ„œλ“œλ₯Ό μ •μ˜ν•  λ•ŒλŠ” μ½€λ§ˆκ°€ ν•„μš” μ—†λ‹€.

3️⃣ μ•”λ¬΅μ μœΌλ‘œ strict mode둜 μ‹€ν–‰λœλ‹€

4️⃣ for ... in λ¬Έμ΄λ‚˜ Object.keys λ©”μ„œλ“œ λ“±μœΌλ‘œ μ—΄κ±°ν•  수 μ—†λ‹€. 즉, ν”„λ‘œνΌν‹°μ˜ μ—΄κ±° κ°€λŠ₯ μ—¬λΆ€λ₯Ό λ‚˜νƒ€λ‚΄λ©°, λΆˆλ¦¬μ–Έ 값을 κ°–λŠ” ν”„λ‘œνΌν‹° μ–΄νŠΈλ¦¬λ·°νŠΈ [[Enumerable]]의 값이 fasleλ‹€.

5️⃣ λ‚΄λΆ€ λ©”μ„œλ“œ [[Construct]]λ₯Ό 갖지 μ•ŠλŠ” non-constructorλ‹€.(newμ—°μ‚°μžμ™€ ν•¨κ»˜ ν˜ΈμΆœν•  수 μ—†λ‹€.)

5-6. 클래슀의 μΈμŠ€ν„΄μŠ€ 생성 κ³Όμ •

1) μΈμŠ€ν„΄μŠ€ 생성과 this 바인딩

  • new μ—°μ‚°μžμ™€ ν•¨κ»˜ 클래슀λ₯Ό ν˜ΈμΆœν•˜λ©΄ μ•”λ¬΅μ μœΌλ‘œ 빈 객체가 생성.
  • ν΄λž˜μŠ€κ°€ μƒμ„±ν•œ μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œν† νƒ€μž… 클래슀의 prototype ν”„λ‘œνΌν‹°λ‘œ 바인딩.
  • μ•”λ¬΅μ μœΌλ‘œ μƒμ„±λœ 빈 객체 즉, μΈμŠ€ν„΄μŠ€λŠ” this에 λ°”μΈλ”©λœλ‹€.

2) μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™”

  • this에 λ°”μΈλ”©λ˜μ–΄ μžˆλŠ” μΈμŠ€ν„΄μŠ€μ— ν”„λ‘œνΌν‹°λ₯Ό μΆ”κ°€ν•˜κ³  constructorκ°€ 인수둜 전달받은 μ΄ˆκΈ°κ°’μœΌλ‘œ μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œνΌν‹° 값을 μ΄ˆκΈ°ν™”ν•œλ‹€.
  • λ§Œμ•½ constructorκ°€ μƒλž΅λ˜μ—ˆλ‹€λ©΄ 이 과정도 μƒλž΅λœλ‹€.

3) μΈμŠ€ν„΄μŠ€ λ°˜ν™˜

클래슀의 λͺ¨λ“  μ²˜λ¦¬κ°€ λλ‚˜λ©΄ μ™„μ„±λœ μΈμŠ€ν„΄μŠ€κ°€ λ°”μΈλ”©λœ thisκ°€ μ•”λ¬΅μ μœΌλ‘œ λ°˜ν™˜λœλ‹€.

class Person {
  // μƒμ„±μž
  constructor(name) {
    // 1. μ•”λ¬΅μ μœΌλ‘œ μΈμŠ€ν„΄μŠ€κ°€ μƒμ„±λ˜κ³  this에 λ°”μΈλ”©λœλ‹€.
    console.log(this); // Person {}
    console.log(Object.getPrototypeOf(this) === Person.prototype); // true

    // 2. this에 λ°”μΈλ”©λ˜μ–΄ μžˆλŠ” μΈμŠ€ν„΄μŠ€λ₯Ό μ΄ˆκΈ°ν™”ν•œλ‹€.
    this.name = name;

    // 3. μ™„μ„±λœ μΈμŠ€ν„΄μŠ€κ°€ λ°”μΈλ”©λœ thisκ°€ μ•”λ¬΅μ μœΌλ‘œ λ°˜ν™˜λœλ‹€.
  }
}

7. ν”„λ‘œνΌν‹°

7-1. μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°

μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°λŠ” constructor λ‚΄λΆ€μ—μ„œ μ •μ˜ν•΄μ•Ό ν•œλ‹€.

class Person {
  constructor(name) {
    // μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°
    this.name = name; // name ν”„λ‘œνΌν‹°λŠ” publicν•˜λ‹€.
  }
}

const me = new Person('Lee);
                      
// name은 publicν•˜λ‹€.                      
console.log(me); // Person {name: "Lee"}
  • constructor μ½”λ“œκ°€ μ‹€ν–‰λ˜κΈ° 이전에 constructor λ‚΄λΆ€μ˜ thisμ—λŠ” 이미 ν΄λž˜μŠ€κ°€ μƒμ„±ν•œ 빈 객체가 λ°”μΈλ”©λ˜μ–΄ μžˆλ‹€.
  • constructor λ‚΄λΆ€μ—μ„œ this에 μΈμŠ€ν„΄μŠ€λ₯Ό ν”„λ‘œνΌν‹°λ₯Ό μΆ”κ°€ν•œλ‹€.
  • constructor λ‚΄λΆ€μ—μ„œ this에 μΆ”κ°€ν•œ ν”„λ‘œνΌν‹°λŠ” μ–Έμ œλ‚˜ ν΄λž˜μŠ€κ°€ μƒμ„±ν•œ μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œνΌν‹°κ°€ λœλ‹€.
  • μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°λŠ” μ–Έμ œλ‚˜ publicν•˜λ‹€.

7-2. μ ‘κ·Όμž ν”„λ‘œνΌν‹°

μ ‘κ·Όμž ν”„λ‘œνΌν‹°λŠ” 자체적으둜 κ°’ [[Value]]을 갖지 μ•Šκ³  λ‹€λ₯Έ 데이터 ν”„λ‘œνΌν‹°μ˜ 값을 μ½κ±°λ‚˜ μ €μž₯ν•  λ•Œ μ‚¬μš©ν•˜λŠ” μ ‘κ·Όμž ν•¨μˆ˜λ‘œ κ΅¬μ„±λœ ν”„λ‘œνΌν‹°λ‹€.

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
  
  // fullName은 μ ‘κ·Όμž ν•¨μˆ˜λ‘œ κ΅¬μ„±λœ μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ‹€.
  // getter ν•¨μˆ˜
  get fullName() {
    return `${this.firstName} ${this.lastName}`
  }
  
  set fullName() {
    [this.firstName, this.lastName] = name.split(' ');
  }
}

const me = new Person('Ungmo', 'Lee');

// 데이터 ν”„λ‘œνΌν‹°λ₯Ό ν†΅ν•œ ν”„λ‘œνΌν‹° κ°’μ˜ μ°Έμ‘°.
console.log(`${me.firstName} ${me.lastName}`) // Ungmo Lee

// μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό ν†΅ν•œ ν”„λ‘œνΌν‹° κ°’μ˜ μ €μž₯
// μ ‘κ·Όμž ν”„λ‘œνΌν‹° fullName에 값을 μ €μž₯ν•˜λ©΄ setter ν•¨μˆ˜κ°€ ν˜ΈμΆœλœλ‹€.
me.fullName = 'Heegun Lee';
console.log(me); // {firstName: 'Heegun', lastName: 'Lee'}

// μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό ν†΅ν•œ ν”„λ‘œνΌν‹° κ°’μ˜ μ°Έμ‘°
// μ ‘κ·Όμž ν”„λ‘œνΌν‹° fullName에 μ ‘κ·Όν•˜λ©΄ getter ν•¨μˆ˜κ°€ ν˜ΈμΆœλœλ‹€.
console.log(me.fullName); // Heegun Lee

// fullName은 μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ‹€.
// μ ‘κ·Όμž ν”„λ‘œνΌν‹°λŠ” get, set, enumerable, configurable ν”„λ‘œνΌν‹° μ–΄νŠΈλ¦¬λ·°νŠΈλ₯Ό κ°–λŠ”λ‹€.
console.log(Object.getOwnPropertyDescriptor(Person.prototype, 'fullName'));
// {get: Ζ’, set: Ζ’, enumerable: false, configurable: true}

1️⃣ μ ‘κ·Όμž ν”„λ‘œνΌν‹°λŠ” ν΄λž˜μŠ€μ—μ„œλ„ μ‚¬μš©ν•  수 μžˆλ‹€.

2οΈβƒ£μ ‘κ·Όμž ν”„λ‘œνΌν‹°λŠ” μžμ²΄μ μœΌλ‘œλŠ” 값을 갖지 μ•Šκ³  λ‹€λ₯Έ 데이터 ν”„λ‘œνΌν‹°μ˜ 값을 μ½κ±°λ‚˜ μ €μž₯ν•  λ•Œ μ‚¬μš©ν•˜λŠ” μ ‘κ·Όμž ν•¨μˆ˜, 즉 getterν•¨μˆ˜μ™€ setterν•¨μˆ˜λ‘œ κ΅¬μ„±λ˜μ–΄ μžˆλ‹€.

3️⃣getterλŠ” λ©”μ„œλ“œ 이름 μ•žμ— get ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄ μ •μ˜ν•œλ‹€.

4️⃣setterλŠ” λ©”μ„œλ“œ 이름 μ•žμ— setν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄ μ •μ˜ν•œλ‹€.

5️⃣getterλŠ” μ°Έμ‘°ν•˜λŠ” ν˜•μ‹μœΌλ‘œ μ‚¬μš©λ˜λ©°, 무언가λ₯Ό 취득할 λ•Œ μ‚¬μš©ν•˜λ―€λ‘œ λ°˜λ“œμ‹œ 무언가λ₯Ό λ°˜ν™˜ν•΄μ•Ό ν•œλ‹€.

6️⃣setterλŠ” ν”„λ‘œνΌν‹°μ— ν• λ‹Ήν•΄μ•Ό ν•  λ•Œ μ‚¬μš©ν•˜λ―€λ‘œ λ°˜λ“œμ‹œ λ§€κ°œλ³€μˆ˜κ°€ μžˆμ–΄μ•Ό ν•œλ‹€.

7️⃣getter setter 이름은 μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°μ²˜λŸΌ μ‚¬μš©λœλ‹€.

8οΈβƒ£μ ‘κ·Όμž ν”„λ‘œνΌν‹°λŠ” μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œλ‘œνƒ€μž…μ΄ μ•„λ‹ˆλΌ ν”„λ‘œν† νƒ€μž…μ˜ ν”„λ‘œνΌν‹°κ°€ λœλ‹€.

7-3. 클래슀 ν•„λ“œ μ •μ˜ μ œμ•ˆ

클래슀 ν•„λ“œ(ν•„λ“œ λ˜λŠ” 맴버)λž€, 클래슀 기반 객체지ν–₯ μ–Έμ–΄μ—μ„œ ν΄λž˜μŠ€κ°€ 생성할 μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œνΌν‹°λ₯Ό κ°€λ¦¬ν‚€λŠ” μš©μ–΄λ‹€.

μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ 클래슀 λͺΈμ²΄μ—λŠ” λ©”μ„œλ“œλ§Œ μ„ μ–Έν•  수 μžˆλ‹€. λ”°λΌμ„œ 클래슀 λͺΈμ²΄μ— 클래슀 ν•„λ“œλ₯Ό μ„ μ–Έν•˜λ©΄ SyntaxErrorκ°€ λ°œμƒν•œλ‹€.

class Person {
  // 클래슀 ν•„λ“œ μ •μ˜
  name = 'Lee';
}

const me = new Person();
console.log(me); // Person {name: "Lee"}

ν•˜μ§€λ§Œ μœ„ 예제λ₯Ό μ΅œμ‹  λΈŒλΌμš°μ €(Chrome 72 이상) λ˜λŠ” μ΅œμ‹  Node.js(버전 12 이상)μ—μ„œ μ‹€ν–‰ν•˜λ©΄ SyntaxErrorκ°€ λ°œμƒν•˜μ§€ μ•Šκ³  정상 λ™μž‘ν•œλ‹€.

κ·Έ μ΄μœ λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œλ„ μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°λ₯Ό 마치 클래슀 기반 객체지ν–₯ μ–Έμ–΄μ˜ 클래슀 ν•„λ“œμ²˜λŸΌ μ •μ˜ν•  수 μžˆλŠ” μƒˆλ‘œμš΄ ν‘œμ€€ 사양인 β€œClass field declarationsβ€œκ°€ TC39ν”„λ‘œμ„ΈμŠ€μ˜ stage 3(candidate)에 μ œμ•ˆλ˜μ–΄ 있기 λ•Œλ¬Έμ΄λ‹€.

TC39 ν”„λ‘œμ„ΈμŠ€

클래슀 λͺΈμ²΄μ—μ„œ 클래슀 ν•„λ“œλ₯Ό μ •μ˜ν•˜λŠ” 경우 this에 클래슀 ν•„λ“œλ₯Ό 바인딩 ν•΄μ„œλŠ” μ•ˆλœλ‹€. thisλŠ” 클래슀의 constructor와 λ©”μ„œλ“œ λ‚΄μ—μ„œλ§Œ μœ νš¨ν•˜λ‹€.

class Person {
  // this에 클래슀 ν•„λ“œλ₯Ό λ°”μΈλ”©ν•΄μ„œλŠ” μ•ˆλœλ‹€.
  this.name = ''; // SyntaxError: Unexpected token '.'
}
  • 클래슀 ν•„λ“œλ₯Ό μ°Έμ‘°ν•˜λŠ” 경우 μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œλŠ” thisλ₯Ό λ°˜λ“œμ‹œ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.
class Person {
  // 클래슀 ν•„λ“œ
  name = 'Lee';

  constructor() {
    // μ°Έμ‘°ν• λ•ŒλŠ” thisλ₯Ό λ°˜λ“œμ‹œ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.
    console.log(name); // ReferenceError: name is not defined
  }
}

new Person();
  • 클래슀 ν•„λ“œμ— μ΄ˆκΈ°κ°’μ„ ν• λ‹Ήν•˜μ§€ μ•ŠμœΌλ©΄ undefinedλ₯Ό κ°–λŠ”λ‹€.
  • μ΄ˆκΈ°ν™”λŠ” constructorμ—μ„œ ν•΄μ•Ό ν•œλ‹€.
class Person {
  name;

  constructor(name) {
    // μ΄ˆκΈ°ν™”ν•  λ•ŒλŠ” constructorμ—μ„œ ν•΄μ•Όν•œλ‹€.
    // 클래슀 ν•„λ“œ μ΄ˆκΈ°ν™”.
    this.name = name;
  }
}

const me = new Person('Lee');
console.log(me); // Person {name: "Lee"}
  • ν•¨μˆ˜λŠ” 일급 κ°μ²΄μ΄λ―€λ‘œ ν•¨μˆ˜λ₯Ό 클래슀 ν•„λ“œμ— ν• λ‹Ήν•  수 μžˆλ‹€.
  • 클래슀 ν•„λ“œμ— ν•¨μˆ˜λ₯Ό ν• λ‹Ήν•˜λŠ” 경우, 이 ν•¨μˆ˜λŠ” ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œκ°€ μ•„λ‹Œ μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œκ°€ λœλ‹€.(클래슀 ν•„λ“œμ— ν•¨μˆ˜λ₯Ό ν• λ‹Ήν•˜λŠ” 것은 ꢌμž₯ν•˜μ§€ μ•ŠλŠ”λ‹€.)
class Person {
  // 클래슀 ν•„λ“œμ— λ¬Έμžμ—΄μ„ ν• λ‹Ή
  name = 'Lee';

  // 클래슀 ν•„λ“œμ— ν•¨μˆ˜λ₯Ό ν• λ‹Ή
  getName = function () {
    return this.name;
  }
  // ν™”μ‚΄ν‘œ ν•¨μˆ˜λ‘œ μ •μ˜ν•  μˆ˜λ„ μžˆλ‹€.
  // ν™”μ‚΄ν‘œ ν•¨μˆ˜ λ‚΄λΆ€μ˜ thisλŠ” μ–Έμ œλ‚˜ μƒμœ„ μ»¨ν…μŠ€νŠΈμ˜ thisλ₯Ό 가리킨닀.
  // getName = () => this.name;
}

const me = new Person();
console.log(me); // Person {name: "Lee", getName: Ζ’}
console.log(me.getName()); // Lee

7-4. private ν•„λ“œ μ •μ˜ μ œμ•ˆ

μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°λŠ” μΈμŠ€ν„΄μŠ€λ₯Ό 톡해 클래슀 μ™ΈλΆ€μ—μ„œ μ–Έμ œλ‚˜ μ°Έμ‘°ν•  수 μžˆλ‹€. 즉, μ–Έμ œλ‚˜ public이닀.

TC39 ν”„λ‘œμ„ΈμŠ€μ˜ stage 3μ—λŠ” privateλ₯Ό μ •μ˜ ν•  수 μžˆλŠ” μƒˆλ‘œμš΄ ν‘œμ€€ 사양이 μ œμ•ˆ λ˜μ–΄ μžˆλ‹€. ν‘œμ€€ μ‚¬μ–‘μœΌλ‘œ μŠΉκΈ‰μ΄ ν™•μ‹€μ‹œλ˜λŠ” 이 μ œμ•ˆλ„ μ΅œμ‚° λΈŒλΌμš°μ €(Chrome 74 이상)와 μ΅œμ‚° Node.js(버전 12 이상)에 이미 κ΅¬ν˜„λ˜μ–΄ μžˆλ‹€.

privateν•„λ“œμ˜ μ„ λ‘μ—λŠ” #을 λΆ™μ—¬μ€€λ‹€. private ν•„λ“œλ₯Ό μ°Έμ‘°ν•  λ•Œλ„ #을 λΆ™μ—¬μ£Όμ–΄μ•Ό ν•œλ‹€.

class Person {
  // private ν•„λ“œ μ •μ˜
  #name = '';
  
  constructor(name) {
    // private ν•„λ“œ μ°Έμ‘°
    this.#name = name;
  }
}

const me = new Person('Lee');

// private ν•„λ“œ #name은 클래슀 μ™ΈλΆ€μ—μ„œ μ°Έμ‘°ν•  수 μ—†λ‹€.
console.log(me.#name);
// SyntaxError: Private field '#name' must be declared in an enclosing class

클래슀 μ™ΈλΆ€μ—μ„œ private ν•„λ“œμ— 직접 μ ‘κ·Όν•  수 μžˆλŠ” 방법은 μ—†λ‹€. λ‹€λ§Œ μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό 톡해 κ°„μ ‘μ μœΌλ‘œ μ ‘κ·Όν•˜λŠ” 방법은 μœ νš¨ν•˜λ‹€,

class Person {
 // private ν•„λ“œ μ •μ˜
  #name = '';
  constructor(name) {
    this.#name = name;
  }

 // name은 μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ‹€.
get name() {
  // private ν•„λ“œλ₯Ό μ°Έμ‘°ν•˜μ—¬ trimν•œ λ‹€μŒ λ°˜ν™˜ν•œλ‹€.
  return this.#name.trim();
  }
}

const me = new Person('Lee');
console.log(me.name); // Lee

private ν•„λ“œλŠ” λ°˜λ“œμ‹œ 클래슀 λͺΈμ²΄μ— μ •μ˜ν•΄μ•Ό ν•œλ‹€. privagte ν•„λ“œλ₯Ό 직접 contructor에 μ •μ˜ν•˜λ©΄ μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.

class Person {
  constructor(name) {
    // private ν•„λ“œλŠ” 클래슀 λͺΈμ²΄μ—μ„œ μ •μ˜ν•΄μ•Ό ν•œλ‹€.
    this.#name = name;
    // SyntaxError: Private field '#name' must be declared in an enclosing class
  }
}

7-5. static ν•„λ“œ μ •μ˜ μ œμ•ˆ

  • staticν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ static public field, static private field, static private λ©”μ„œλ“œλ₯Ό μ •μ˜ν•  수 μžˆλŠ” μƒˆλ‘œμš΄ ν‘œμ€€ 사양인 β€œStatic class features”가 TC39 ν”„λ‘œμ„ΈμŠ€μ˜ stage 3(candidate)에 μ œμ•ˆλ˜μ–΄ μžˆλ‹€.
  • μ΅œμ‹  λΈŒλΌμš°μ €(chrome 72이상)와 Node.js(버전 12 이상)에 이미 κ΅¬ν˜„λ˜μ–΄ μžˆλ‹€.
class MyMath {
  // static public ν•„λ“œ μ •μ˜
  static PI = 22 / 7;

  // static private ν•„λ“œ μ •μ˜
  static #num = 10;

  // static λ©”μ„œλ“œ
  static increment() {
    return ++MyMath.#num;
  }
}

console.log(MyMath.PI); // 3.142857142857143
console.log(MyMath.increment()); // 11

8. 상속에 μ˜ν•œ 클래슀 ν™•μž₯

8-1. 클래슀 상속과 μƒμ„±μž ν•¨μˆ˜ 상속

상속에 μ˜ν•œ 클래슀 ν™•μž₯은 μ§€κΈˆκΉŒμ§€ μ‚΄νŽ΄λ³Έ ν”„λ‘œν† νƒ€μž… 기반 μƒμ†κ³ΌλŠ” λ‹€λ₯Έ κ°œλ….

ν”„λ‘œν† νƒ€μž… 기반 상속은 ν”„λ‘œν† νƒ€μž… 체인을 톡해 λ‹€λ₯Έ 객체의 μžμ‚°μ„ μƒμ†λ°›λŠ” κ°œλ…μ΄μ§€λ§Œ 상속에 μ˜ν•œ 클래슀 ν™•μž₯은 κΈ°μ‘΄ 클래슀λ₯Ό 상속받아 μƒˆλ‘œμš΄ 클래슀λ₯Ό ν™•μž₯(extends)ν•˜μ—¬ μ •μ˜ν•˜λŠ” 것.

ν΄λž˜μŠ€λŠ” 상속을 톡해 κΈ°μ‘΄ 클래슀λ₯Ό ν™•μž₯ν•  수 μžˆλŠ” 문법이 기본적으둜 μ œκ³΅λ˜μ§€λ§Œ μƒμ„±μž ν•¨μˆ˜λŠ” 그렇지 μ•Šλ‹€.

class Animal {
  constructor(age, weight) {
    this.age = age;
    this.weight = weight;
  }
  
  eat() { return 'eat'; }
  
  move() { return 'move'; }
}

// 상속을 톡해 Animal 클래슀λ₯Ό ν™•μž₯ν•œ Bird 클래슀
class Bird extends Animal {
  fly () { return 'fly'; }
}

const bird = new Bird(1, 5);

console.log(bird); // Bird {age: 1, weight: 5}
console.log(bird instanceof Bird); // true
console.log(bird instanceof Animal); // true

console.log(bird.eat());  // eat
console.log(bird.move()); // move
console.log(bird.fly());  // fly

8-2. extends ν‚€μ›Œλ“œ

상속을 톡해 클래슀λ₯Ό ν™•μž₯ν•˜λ €λ©΄ extends ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ 상속받을 클래슀λ₯Ό μ •μ˜ν•œλ‹€.

// 수퍼(베이슀/λΆ€λͺ¨)클래슀
class Base {}

// μ„œλΈŒ(νŒŒμƒ/μžμ‹)클래슀
class Derived extends Base {}

extends ν‚€μ›Œλ“œ 역할은 μˆ˜νΌν΄λž˜μŠ€μ™€ μ„œλΈŒν΄λž˜μŠ€ κ°„μ˜ 상속 관계λ₯Ό μ„€μ •ν•˜λŠ” 것. ν΄λž˜μŠ€λ„ ν”„λ‘œν† νƒ€μž…μ„ 톡해 상속 관계λ₯Ό κ΅¬ν˜„.

μˆ˜νΌν΄λž˜μŠ€μ™€ μ„œλΈŒν΄λž˜μŠ€λŠ” μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œν† νƒ€μž… 체인뿐 μ•„λ‹ˆλΌ 클래슀 κ°„μ˜ ν”„λ‘œν† νƒ€μž… 체인도 μƒμ„±ν•œλ‹€. 이λ₯Ό 톡해 ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ, 정적 λ©”μ„œλ“œ λͺ¨λ‘ 상속이 κ°€λŠ₯ν•˜λ‹€.

8-3. 동적 상속

extends ν‚€μ›Œλ“œλŠ” 클래슀 뿐만 μ•„λ‹ˆλΌ μƒμ„±μž ν•¨μˆ˜λ₯Ό 상속받아 클래슀λ₯Ό ν™•μž₯ν•  μˆ˜λ„ μžˆλ‹€. 단, extends ν‚€μ›Œλ“œ μ•žμ—λŠ” λ°˜λ“œμ‹œ ν΄λž˜μŠ€κ°€ 와야 ν•œλ‹€.

// μƒμ„±μž ν•¨μˆ˜
function Base(a) {
  this.a = a;
}

// μƒμ„±μž ν•¨μˆ˜λ₯Ό μƒμ†λ°›λŠ” μ„œλΈŒν΄λž˜μŠ€
class Derived extends Base{}

const derived = new Derived(1);
console.log(derived); // Derived {a: 1}

extends ν‚€μ›Œλ“œ λ‹€μŒμ—λŠ” 클래슀뿐만 μ•„λ‹ˆλΌ [[Construct]]λ‚΄λΆ€ λ©”μ„œλ“œλ₯Ό κ°–λŠ” ν•¨μˆ˜ 객체둜 ν‰κ°€λ μˆ˜ μžˆλŠ” λͺ¨λ“  ν‘œν˜„μ‹μ„ μ‚¬μš©ν•  수 μžˆλ‹€.(이λ₯Ό 톡해 λ™μ μœΌλ‘œ 상속가λŠ₯)

function Base1() {}

class Base2 {}

let condition = true;

// 쑰건에 따라 λ™μ μœΌλ‘œ 상속 λŒ€μƒμ„ κ²°μ •ν•˜λŠ” μ„œλΈŒν΄λž˜μŠ€
class Derived extends (condition ? Base1 : Base2) {}

const derived = new Derived();
console.log(derived); // Derived {}

console.log(derived instanceof Base1); // true
console.log(derived instanceof Base2); // false

8-4. μ„œλΈŒν΄λž˜μŠ€μ˜ constructor

μ„œλΈŒν΄λž˜μŠ€μ—μ„œ constructorλ₯Ό μƒλž΅ν•˜λ©΄ μ•”λ¬΅μ μœΌλ‘œ μ •μ˜λœλ‹€.

// 수퍼클래슀
class Base {}

// μ„œλΈŒν΄λž˜μŠ€
class Derived extends Base {}

μœ„ 와 같이 μƒλž΅λœ 경우 μ•„λž˜μ™€ 같이 μ•”λ¬΅μ μœΌλ‘œ μƒμ„±λœλ‹€.

// 수퍼클래슀
class Base {
  constructor() {}
}

// μ„œλΈŒν΄λž˜μŠ€
class Derived extends Base {
  constructor() { super(); }
}

const derived = new Derived();
console.log(derived); // Derived {}

8-5. super ν‚€μ›Œλ“œ

super ν‚€μ›Œλ“œλŠ” ν•¨μˆ˜μ²˜λŸΌ ν˜ΈμΆœν•  수 도 있고 this와 같이 μ‹λ³„μžμ²˜λŸΌ μ°Έμ‘°ν•  수 μžˆλŠ” νŠΉμˆ˜ν•œ ν‚€μ›Œλ“œλ‹€.

βœ“ superλ₯Ό ν˜ΈμΆœν•˜λ©΄ 수퍼클래슀의 constructor(super-construcotr)λ₯Ό ν˜ΈμΆœν•œλ‹€.
**βœ“ superλ₯Ό μ°Έμ‘°ν•˜λ©΄ 수퍼클래슀의 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•  수 μžˆλ‹€.

❗️ super 호좜

superλ₯Ό ν˜ΈμΆ”ν•˜λ©΄ 수퍼클래슀의 constructor(super-constructor)λ₯Ό ν˜ΈμΆœν•œλ‹€.

수퍼클래슀의 constructor λ‚΄λΆ€μ—μ„œ μΆ”κ°€ν•œ ν”„λ‘œνΌν‹°λ₯Ό κ·ΈλŒ€λ‘œ κ°–λŠ” μΈμŠ€ν„΄μŠ€λ₯Ό 생성 ν•œλ‹€λ©΄ μ„œλΈŒν΄λž˜μŠ€μ˜ construcotrλ₯Ό μƒλž΅ν•  수 μžˆλ‹€. μ΄λ•Œ new μ—°μ‚°μžμ™€ ν•¨κ»˜ μ„œλΈŒν΄λž˜μŠ€λ₯Ό ν˜ΈμΆœν•˜λ©΄ μ „λ‹¬ν•œ μΈμˆ˜λŠ” λͺ¨λ‘ μ„œλΈŒν΄λž˜μŠ€μ— μ•”λ¬΅μ μœΌλ‘œ μ •μ˜λœ construcotr의 super ν˜ΈμΆœμ„ 톡해 수퍼클래슀의 constructor에 μ „λ‹¬λœλ‹€.

// 수퍼클래슀
class Base {
  constructor(a, b) {
    this.a = a;
    this.b = b;
  }
}

// μ„œλΈŒν΄λž˜μŠ€
class Derived extends Base {
  // λ‹€μŒκ³Ό 같이 μ•”λ¬΅μ μœΌλ‘œ constructorκ°€ μ •μ˜λœλ‹€.
  // constructor(...args) { super(...args); }
}

const derived = new Derived(1, 2);
console.log(derived); // Derived {a: 1, b: 2}
  • μ„œλΈŒν΄λž˜μŠ€μ—μ„œ constructorλ₯Ό μƒλž΅ν•˜μ§€ μ•ŠλŠ” 경우 μ„œλΈŒν΄λž˜μŠ€μ˜ constructorμ—μ„œλŠ” λ°˜λ“œμ‹œ superλ₯Ό ν˜ΈμΆœν•΄μ•Ό ν•œλ‹€.
class Base {}

class Derived extends Base {
  constructor() {
    // ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
    console.log('constructor call');
  }
}

const derived = new Derived();
  • μ„œλΈŒν΄λž˜μŠ€μ˜ constructorμ—μ„œ superλ₯Ό ν˜ΈμΆœν•˜κΈ° μ „μ—λŠ” thisλ₯Ό μ°Έμ‘°ν•  수 μ—†λ‹€.(μΈμŠ€ν„΄μŠ€ 생성과 this바인딩은 μˆ˜νΌν΄λž˜μŠ€μ—μ„œ ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.)
class Base {}

class Derived extends Base {
  constructor() {
    // ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
    this.a = 1;
    super();
  }
}

const derived = new Derived(1);
  • superλŠ” λ°˜λ“œμ‹œ μ„œλΈŒν΄λž˜μŠ€μ˜ constructorμ—μ„œλ§Œ ν˜ΈμΆœν•œλ‹€. μ„œλΈŒν΄λž˜μŠ€κ°€ μ•„λ‹Œ 클래슀의 consturcotrλ‚˜ ν•¨μˆ˜μ—μ„œ superλ₯Ό ν˜ΈμΆœν•˜λ©΄ μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.
class Base {
  constructor() {
    super(); // SyntaxError: 'super' keyword unexpected here
  }
}

function Foo() {
  super(); // SyntaxError: 'super' keyword unexpected here
}

❗️super μ°Έμ‘°

λ©”μ„œλ“œ λ‚΄μ—μ„œ superλ₯Ό μ°Έμ‘°ν•˜λ©΄ 수퍼클래슀의 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•  수 μžˆλ‹€.

μ„œλΈŒν΄λž˜μŠ€μ˜ ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ λ‚΄μ—μ„œ super.sayHiλŠ” 수퍼클래슀의 ν”„ν† ν† νƒ€μž… λ©”μ„œλ“œ sayHiλ₯Ό 가리킨닀.

// 수퍼클래슀
class Base {
  constructor(name) {
    this.name = name;
  }
  
  sayHi() {
    return `Hi ${this.name}`'
  }
}

// μ„œλΈŒν΄λž˜μŠ€ 
class Derived extends Base {
  sayHi() {
    // super.sayHiλŠ” 수퍼클래슀의 ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œλ₯Ό 가리킨닀.
    return `${super.sayHi()}. how are you doing?`;
  }
}

const derived = new Derived('Lee');
console.log(derived.sayHi()); // Hi! Lee. how are you doing

super.sayHiλŠ” Base.prototype.sayHiλ₯Ό 가리킨닀.
즉 superλŠ” μžμ‹ μ„ μ°Έμ‘°ν•˜κ³  μžˆλŠ” λ©”μ„œλ“œκ°€ 바인딩 λ˜μ–΄μžˆλŠ” 객체의 ν”„λ‘œν† νƒ€μž…μ„ 가리킨닀.(Derived의 sayHi λ©”μ„œλ“œκ°€ 바인딩 λ˜μ–΄μžˆλŠ” 객체 derived의 ν”„λ‘œν† νƒ€μž…μΈ Base.prototype을 가리킨닀.)

super참쑰의 λ™μž‘μ€ Derived클래슀의 sayHiλ©”μ„œλ“œμ˜ [[HomeObject]]λ‚΄λΆ€ μŠ¬λ‘―μ„ 톡해 μžμ‹ μ„ λ°”μΈλ”©ν•˜λŠ” 객체λ₯Ό μ•Œμˆ˜μžˆλ‹€.

μžμ‹ μ„ λ°”μΈλ”©ν•˜λŠ” 객체λ₯Ό μ•Œλ©΄ ν”„λ‘œν† νƒ€μž… 체인을 톡해 superλ₯Ό μ°Έμ‘°ν•  수 μžˆκ²Œλœλ‹€.

μ£Όμ˜ν•  점은 ES6의 λ©”μ„œλ“œ μΆ•μ•½ ν‘œν˜„μœΌλ‘œ μ •μ˜λœ ν•¨μˆ˜λ§Œ [[HomeObject]]λ₯Ό κ°–λŠ”λ‹€λŠ” 것이닀.

const obj = {
  // fooλŠ” ES6의 λ©”μ„œλ“œ μΆ•μ•½ ν‘œν˜„μœΌλ‘œ μ •μ˜ν•œ λ©”μ„œλ“œλ‹€. λ”°λΌμ„œ [[HomeObject]]λ₯Ό κ°–λŠ”λ‹€.
  foo() {},

  // barλŠ” ES6의 λ©”μ„œλ“œ μΆ•μ•½ ν‘œν˜„μœΌλ‘œ μ •μ˜ν•œ λ©”μ„œλ“œκ°€ μ•„λ‹ˆλΌ 일반 ν•¨μˆ˜λ‹€.
  // λ”°λΌμ„œ [[HomeObject]]λ₯Ό 갖지 μ•ŠλŠ”λ‹€.
  bar: function () {}
};

superμ°Έμ‘°λŠ” 객체 λ¦¬ν„°λŸ΄μ—μ„œλ„ ν• μˆ˜ μžˆλ‹€.(단, ES6의 λ©”μ„œλ“œ μΆ•μ•½ν‘œν˜„μœΌλ‘œ μ •μ˜λœ ν•¨μˆ˜λ§Œ κ°€λŠ₯ν•˜λ‹€.)

const base = {
  name: 'Lee',
  sayHi() {
    return `Hi! ${this.name}`;
  }
};

const derived = {
  __proto__: base,
  // ES6 λ©”μ„œλ“œ μΆ•μ•½ ν‘œν˜„μœΌλ‘œ μ •μ˜ν•œ λ©”μ„œλ“œλ‹€. λ”°λΌμ„œ [[HomeObject]]λ₯Ό κ°–λŠ”λ‹€.
  sayHi() {
    return `${super.sayHi()}. how are you doing?`;
  }
};

console.log(derived.sayHi()); // Hi! Lee. how are you doing?

μ„œλΈŒν΄λž˜μŠ€μ˜ 정적 λ©”μ„œλ“œ λ‚΄μ—μ„œ super.sayHiλŠ” 수퍼클래슀의 정적 λ©”μ„œλ“œ sayHiλ₯Ό 가리킨닀.

// 수퍼클래슀
class Base {
  static sayHi() {
    return 'Hi!';
  }
}

// μ„œλΈŒν΄λž˜μŠ€
class Derived extends Base {
  static sayHi() {
    // super.sayHiλŠ” 수퍼클래슀의 정적 λ©”μ„œλ“œλ₯Ό 가리킨닀.
    return `${super.sayHi()} how are you doing?`;
  }
}

console.log(Derived.sayHi()); // Hi! how are you doing?

8-6. 상속 클래슀의 μΈμŠ€ν„΄μŠ€ 생성 κ³Όμ •

상속 관계에 μžˆλŠ” 두 ν΄λž˜μŠ€κ°€ μ–΄λ–»κ²Œ ν˜‘λ ₯ν•˜λ©° μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λŠ”μ§€ μ‚΄νŽ΄λ³΄λ„λ‘ ν•˜μž

// 수퍼클래슀
class Rectangle {
  construcotor(width, height) {
    this.width = width;
    this.height = height;
  }
  
  getArea() {
    return this.width * this.height;
  }
  
  toString() {
    return `width = ${this.width}, height = ${this.height}`;
  }
}

// μ„œλΈŒ 클래슀
class ColorRectangle extends Rectangle {
  construcotor(width, height, color) {
    super(width, height);
    this.color = color;
  }
  
  // λ§€μ„œλ“œ μ˜€λ²„λΌμ΄λ”© 
  toString() {
  	return super.toString() + `, color = ${this.color}`;
  }
}

const colorRectangle = new ColorRectangle(2,4, 'red');
console.log(colorRectangle); // ColorRectangle {width: 2, height: 4, color: "red"}

// 상속을 톡해 getArea λ©”μ„œλ“œλ₯Ό 호좜
console.log(colorRectangle.getArea()); // 8
// μ˜€λ²„λΌμ΄λ”©λœ toString λ©”μ„œλ“œλ₯Ό 호좜
console.log(colorRectangle.toString()); // width = 2, height = 4, color = red

1) μ„œλΈŒν΄λž˜μŠ€μ˜ super 호좜

μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진은 클래슀λ₯Ό 평가할 λ•Œ μˆ˜νΌν΄λž˜μŠ€μ™€ μ„œλΈŒν΄λž˜μŠ€λ₯Ό κ΅¬λΆ„ν•˜κΈ° μœ„ν•΄ base λ˜λŠ” derivedλ₯Ό κ°’μœΌλ‘œ κ°–λŠ” λ‚΄λΆ€ 슬둯 [[ConstructorKind]]λ₯Ό κ°–λŠ”λ‹€.

μ„œλΈŒν΄λž˜μŠ€λŠ” μžμ‹ μ΄ 직접 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜μ§€ μ•Šκ³  μˆ˜νΌν΄λž˜μŠ€μ—κ²Œ μΈμŠ€ν„΄μŠ€ 생성을 μœ„μž„ν•œλ‹€. 이것이 λ°”λ‘œ μ„œλΈŒν΄λž˜μŠ€μ˜ constructorμ—μ„œ λ°˜λ“œμ‹œ superλ₯Ό ν˜ΈμΆœν•΄μ•Ό ν•˜λŠ” μ΄μœ λ‹€.

μ„œλΈŒν΄λž˜μŠ€κ°€ new μ—°μ‚°μžμ™€ ν•¨κ»˜ 호좜되면 μ„œλΈŒν΄λž˜μŠ€ constructor λ‚΄λΆ€μ˜ super ν‚€μ›Œλ“œκ°€ ν•¨μˆ˜μ²˜λŸΌ ν˜ΈμΆœλœλ‹€.(μˆ˜νΌν΄λž˜μŠ€κ°€ ν‰κ°€λ˜μ–΄ μƒμ„±λœ ν•¨μˆ˜ 객체의 μ½”λ“œκ°€ μ‹€ν–‰λ˜κΈ° μ‹œμž‘ν•œλ‹€.)

μ„œλΈŒν΄λž˜μŠ€ constructor 내뢀에 super 호좜이 μ—†μœΌλ©΄ μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.

2) 수퍼클래슀의 μΈμŠ€ν„΄μŠ€ 생성과 this 바인딩

수퍼클래슀의 constructor λ‚΄λΆ€μ˜ μ½”λ“œκ°€ μ‹€ν–‰λ˜κΈ° 이전에 μ•”λ¬΅μ μœΌλ‘œ 빈 객체λ₯Ό μƒμ„±ν•œλ‹€. 이 빈 객체가 λ°”λ‘œ(아직 μ•ˆλ˜μ§€λŠ” μ•Šμ•˜μ§€λ§Œ) ν΄λž˜μŠ€κ°€ μƒμ„±ν•œ μΈμŠ€ν„΄μŠ€λ‹€.

μ•”λ¬΅μ μœΌλ‘œ μƒμ„±λœ 빈 객체, 즉 μΈμŠ€ν„΄μŠ€λŠ” this에 λ°”μΈλ”©λœλ‹€. λ”°λΌμ„œ 수퍼클래슀의 constructor λ‚΄λΆ€μ˜ thisλŠ” μƒμ„±λœ μΈμŠ€ν„΄μŠ€λ₯Ό 가리킨닀.

// 수퍼클래슀 
class Rectangle {
  constructor(width, height) {
    // μ•”λ¬΅μ μœΌλ‘œ 빈 객체, 즉 μΈμŠ€ν„΄μŠ€κ°€ μƒμ„±λ˜κ³  this에 λ°”μΈλ”©λœλ‹€.
    console.log(this); // ColorRectangle {}
    // new μ—°μ‚°μžμ™€ ν•¨κ»˜ ν˜ΈμΆœν•œ ν•¨μˆ˜, 즉 new.target은 ColorRectangle이닀.
    console.log(new.target); // ColorRectangle 
    
    // μƒμ„±λœ μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œν† νƒ€μž…μœΌλ‘œ ColorRectangle.prototype이 μ„€μ •λœλ‹€.
    console.log(Object.getPrototypeOf(this) === ColorRectangle.prototype); // true
    console.log(this instanceof ColorRectangle); // true
    console.log(this instanceof Rectangle); // true
  }

μΈμŠ€ν„΄μŠ€ μˆ˜νΌν΄λž˜μŠ€κ°€ μƒμ„±ν•œ 것. ν•˜μ§€λ§Œ new μ—°μ‚°μžμ™€ ν•¨κ»˜ 호좜된 ν΄λž˜μŠ€κ°€ μ„œλΈŒν΄λž˜μŠ€λΌλŠ” 것이 μ€‘μš”.

new.target은 μ„œλΈŒν΄λž˜μŠ€λ₯Ό 가리킨닀. λ”°λΌμ„œ μΈμŠ€ν„΄μŠ€λŠ” new.target이 κ°€λ¦¬ν‚€λŠ” μ„œλΈŒν΄λž˜μŠ€κ°€ μƒμ„±ν•œ κ²ƒμœΌλ‘œ μ²˜λ¦¬λœλ‹€.

μƒμ„±λœ μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œν† νƒ€μž…μ€ μ„œλΈŒν΄λž˜μŠ€μ˜ prototype ν”„λ‘œνΌν‹°κ°€ κ°€λ¦¬ν‚€λŠ” 객체(Colorrectangle.prototype)λ‹€.

3) 수퍼클래슀의 μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™”

수퍼클래슀의 constructorκ°€ μ‹€ν–‰ this에 λ°”μΈλ”©λ˜μ–΄ μžˆλŠ” μΈμŠ€ν„΄μŠ€λ₯Ό μ΄ˆκΈ°ν™”.

// 수퍼클래슀
class Rectangle {
  constructor(width, height) {
    // μ•”λ¬΅μ μœΌλ‘œ 빈 객체, 즉 μΈμŠ€ν„΄μŠ€κ°€ μƒμ„±λ˜κ³  this에 λ°”μΈλ”©λœλ‹€.
    console.log(this); // ColorRectangle {}
    // new μ—°μ‚°μžμ™€ ν•¨κ»˜ 호좜된 ν•¨μˆ˜, 즉 new.target은 ColorRectangle이닀.
    console.log(new.target); // ColorRectangle 
    
    // μƒμ„±λœ μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œν† νƒ€μž…μœΌλ‘œ ColorRectangle.prototype이 μ„€μ •λœλ‹€.
    console.log(Object.getPrototypeOf(this) === ColorRectangle.prototype); // true
    console.log(this instanceof ColorRectangle); // true
    console.log(this instanceof Rectangle); // true
    
    // μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™”
    this.widht = width;
    this.height = height;
    
    console.log(this); // ColorRectangle {width:2, height:4}

4) μ„œλΈŒν΄λž˜μŠ€ constructor둜의 볡귀와 this 바인딩

super 호좜이 μ’…λ£Œλ˜κ³  μ œμ–΄ 흐름이 μ„œλΈŒν΄λž˜μŠ€ constructor둜 λŒμ•„μ˜¨λ‹€.

μ΄λ•Œ superκ°€ λ°˜ν™˜ν•œ μΈμŠ€ν„΄μŠ€κ°€ this에 바인딩 μ„œλΈŒν΄λž˜μŠ€λŠ” λ³„λ„μ˜ μΈμŠ€ν„΄μŠ€ μƒμ„±ν•˜μ§€ μ•ŠμŒ.

// μ„œλΈŒν΄λž˜μŠ€
class ColorRectangle extends Rectangle {
	constructor(width, height, color) {
      super(width, height);
      
      // superκ°€ λ°˜ν™˜ν•œ μΈμŠ€ν„΄μŠ€κ°€ this에 λ°”μΈλ”©λœλ‹€.
      console.log(this); // ColorRectangle {widht: 2, height: 4}

이 처럼 superκ°€ ν˜ΈμΆœλ˜μ§€ μ•ŠμœΌλ©΄ μΈμŠ€ν„΄μŠ€κ°€ μƒμ„±λ˜μ§€ μ•ŠμœΌλ©°, this도 바인딩 ν•  수 μ—†λ‹€. μ„œλΈŒν΄λž˜μŠ€μ˜ constructorμ—μ„œ superλ₯Ό ν˜ΈμΆœν•˜κΈ° μ „μ—λŠ” thisλ₯Ό μ°Έμ‘°ν•  수 μ—†λŠ” μ΄μœ κ°€ λ°”λ‘œ 이 λ•Œλ¬Έμ΄λ‹€.

5) μ„œλΈŒν΄λž˜μŠ€μ˜ μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™”

super 호좜 이후, μ„œλΈŒν΄λž˜μŠ€μ˜ constructor에 κΈ°μˆ λ˜μ–΄ μžˆλŠ” μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™”

6) μΈμŠ€ν„΄μŠ€ λ°˜ν™˜

클래슀의 λͺ¨λ“  μ²˜λ¦¬κ°€ λλ‚˜λ©΄ μ™„μ„±λœ μΈμŠ€ν„΄μŠ€κ°€ λ°”μΈλ”©λœ thisκ°€ μ•”λ¬΅μ μœΌλ‘œ λ°˜ν™˜.

// μ„œλΈŒν΄λž˜μŠ€
class ColorRectangle extends Rectangle {
  constructor(width, height, color) {
    super(width, height);

    // superκ°€ λ°˜ν™˜ν•œ μΈμŠ€ν„΄μŠ€κ°€ this에 λ°”μΈλ”©λœλ‹€.
    console.log(this); // ColorRectangle {width: 2, height: 4}

    // μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™”
    this.color = color;

    // μ™„μ„±λœ μΈμŠ€ν„΄μŠ€κ°€ λ°”μΈλ”©λœ thisκ°€ μ•”λ¬΅μ μœΌλ‘œ λ°˜ν™˜λœλ‹€.
    console.log(this); // ColorRectangle {width: 2, height: 4, color: "red"}
  }
...

8-7. ν‘œμ€€ 빌트인 μƒμ„±μž ν•¨μˆ˜ ν™•μž₯

extends ν‚€μ›Œλ“œ λ‹€μŒμ—λŠ” 클래슀 뿐만 μ•„λ‹ˆλΌ [[Construct]] λ‚΄λΆ€ λ©”μ„œλ“œλ₯Ό κ°–λŠ” ν•¨μˆ˜ 객체둜 평가 될 수 μžˆλŠ” λͺ¨λ“  ν‘œν˜„μ‹ μ‚¬μš© κ°€λŠ₯.

String Number Array 같은 ν‘œμ€€ 빌트인 객체도 [[Construct]] λ‚΄λΆ€ λ©”μ„œλ“œλ₯Ό κ°–λŠ” μƒμ„±μž ν•¨μˆ˜μ΄λ―€λ‘œ extends ν‚€μ›Œλ“€ μ‚¬μš©ν•˜μ—¬ ν™•μž₯ν•  수 μžˆλ‹€.

// Array μƒμ„±μž ν•¨μˆ˜λ₯Ό 상속받아 ν™•μž₯ν•œ MyArray
class MyArray extends Array {
  // μ€‘λ³΅λœ λ°°μ—΄ μš”μ†Œλ₯Ό μ œκ±°ν•˜κ³  λ°˜ν™˜ν•œλ‹€: [1,1,2,3] => [1,2,3]
  uniq() {
    return this.filter((v, i, self) => self.indexOf(v) === i);
  }
  
  // λͺ¨λ“  λ°°μ—΄ μš”μ†Œμ˜ 평균을 κ΅¬ν•œ: [1, 2, 3] => 2
  average() {
    return this.reduce((pre, cur) => pre + cur, 0); / this.length;
  }
}

const myArray = new MyArray(1, 1, 2, 3);
console.log(myArray); // MyArray(4) [1, 1, 2, 3]

// MyArray.prototype.unip 호좜
console.log(myArray.uniq()); // MyArray(4) [1, 2, 3]
// MyArray.prootype.average 호좜
console.log(myArray.average()); // 1.75

Array μƒμ„±μž ν•¨μˆ˜λ₯Ό 상속받아 ν™•μž₯ν•œ MyArray ν΄λž˜μŠ€κ°€ μƒμ„±ν•œ μΈμŠ€ν„΄μŠ€λŠ” Array.prototypeκ³Ό MyArray.prototype의 λͺ¨λ“  λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

μ£Όμ˜ν•  것은 Arrray.prototype의 λ©”μ„œλ“œ 쀑에 map filter와 같이 μƒˆλ‘œμš΄ 배열을 λ°˜ν™˜ν•˜λŠ” λ©”μ„œλ“œκ°€ MyArray 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•œλ‹€λŠ” 것.

console.log(myArray.filter(v => v % 2) instanceof MyArray); // true

λ§Œμ•½ μƒˆλ‘œμš΄ 배열은 λ°˜ν™˜ν•˜λŠ” λ§€μ„œλ“œκ°€ MyArray 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•˜μ§€ μ•Šκ³  Array의 μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•˜λ©΄ MyArray 클래슀의 λ©”μ„œλ“œμ™€ λ©”μ„œλ“œμ²΄μ΄λ‹μ΄ λΆˆκ°€λŠ₯ν•˜λ‹€.

πŸ’‘ λ©”μ„œλ“œ μ²΄μ΄λ‹μ΄λž€?

λ©”μ„œλ“œκ°€ 객체λ₯Ό λ°˜ν™˜ν•˜κ²Œ 되면 λ©”μ„œλ“œμ˜ λ°˜ν™˜ 값인 객체λ₯Ό 톡해 또 λ‹€λ₯Έ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  수 μžˆλ‹€. μ΄λŸ¬ν•œ ν”„λ‘œκ·Έλž˜λ° νŒ¨ν„΄μ„ λ©”μ„œλ“œ 체이닝(Method Chaining)이라 λΆ€λ₯Έλ‹€.

// λ©”μ„œλ“œ 체이닝
// [1, 1, 2, 3] => [1, 1, 3] => [1, 3] => 2
console.log(myArray.filter(v => v%2).uniq().average()); // 2

λ§Œμ•½ MyArray 클래슀의 uniq λ©”μ„œλ“œκ°€ MyArray ν΄λž˜μŠ€κ°€ μƒμ„±ν•œ μΈμŠ€ν„΄κ°€ μ•„λ‹Œ Arrayκ°€ μƒμ„±ν•œ μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•˜κ²Œ ν•˜λ €λ©΄ λ‹€μŒκ³Ό 같이 Symbol.speciesλ₯Ό μ‚¬μš©ν•˜μ—¬ 정적 μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό μΆ”κ°€ν•œλ‹€.

// Array μƒμ„±μž ν•¨μˆ˜λ₯Ό 상속받아 ν™•μž₯ν•œ MyArray
class MyArray extends Array {
  // λͺ¨λ“  λ©”μ„œλ“œκ°€ Array νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•˜λ„λ‘ ν•œλ‹€.
  static get [Symbol.species]() { return Array; }
  
  // μ€‘λ³΅λœ λ°°μ—΄ μš”μ†Œλ₯Ό μ œκ±°ν•˜κ³  λ°˜ν™˜ν•œλ‹€: [1, 1, 2, 3] => [1, 2, 3]
  uniq() {
    return this.filter((v, i, self) => self.indexOf(v) === i);
  }
  
  // λͺ¨λ“  λ°°μ—΄ μš”μ†Œμ˜ 평균을 κ΅¬ν•œλ‹€: [1, 2, 3] => 2
  average() {
    return this.reduce((pre, cur) => prec + cur, 0) / this.length;
  }
}

const myArray = new MyArray(1, 1, 2, 3);

console.log(myArray.uniq() instanceof MyArray); // false
console.log(myArray.uniq() instanceof Array); // true

// λ©”μ„œλ“œ 체이닝
// uniq λ©”μ„œλ“œλŠ” Array μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•˜λ―€λ‘œ average λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•  수 μ—†λ‹€.
console.log(myArray.uniq().average());
// TypeError: myArray.uniq(...).average is not a function
post-custom-banner

0개의 λŒ“κΈ€