javascript classes - Lee-hyuna/33-js-concepts-kr GitHub Wiki

Javascript Classesβ€Šβ€”β€ŠUnder The Hood

원문: Javascript Classesβ€Šβ€”β€ŠUnder The Hood

μžλ°”μŠ€ν¬λ¦½νŠΈ ν΄λž˜μŠ€λŠ” 기쑴의 ν”„λ‘œν† νƒ€μž… 기반 상속 및 μƒμ„±μž ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•œ νŽΈμ˜λ¬Έλ²•μ΄λ‹€. JS 클래슀의 이면에 μžˆλŠ” 아이디어λ₯Ό μ΄ν•΄ν•˜κΈ° μœ„ν•΄μ„œλŠ” μƒμ„±μž ν•¨μˆ΄, ν”„λ‘œν† νƒ€μž… 및 기타 κ΄€λ ¨ κ°œλ…μ„ 이해할 ν•„μš”κ°€ μžˆλ‹€.

1. μƒμ„±μž ν•¨μˆ˜ (constructor function)

JavascriptλŠ” λͺ¨λ“  것이 단지 ν•¨μˆ˜μΈ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ° 언어이기 λ•Œλ¬Έμ—, 클래슀λ₯Ό λ§Œλ“€κΈ° μœ„ν•΄ μƒμ„±μž ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” 경우, μƒμ„±μž ν•¨μˆ˜κ°€ μ–΄λ–»κ²Œ μž‘λ™ν•˜λŠ”μ§€ μ•Œμ•„λ³΄μž.

function Vehicle(make, model, color) {  
  this.make = make,  
  this.model = model,  
  this.color = color,  
  this.getName = function () {  
    return this.make + " " + this.model
  }
}

μœ„μ˜ ν•¨μˆ˜λŠ” Java의 ν΄λž˜μŠ€μ™€ 거의 μœ μ‚¬ν•œ κΈ°λŠ₯을 μ œκ³΅ν•œλ‹€. ν•΄λ‹Ή ν•¨μˆ˜λ₯Ό μ΄μš©ν•˜μ—¬ Vehicle μœ ν˜•μ˜ 객체λ₯Ό μƒμ„±ν•˜κΈ° μœ„ν•΄ λ‹€μŒκ³Ό 같이 ν•œλ‹€.:

let car = new Vehicle("Toyota", "Corolla", "Black")
let car2= new Vehicle("Honda", "Civic", "White")

이건 μ™„λ²½ν•˜λ‹€. 그렇지? 이제, 단지 ν•œμ€„μ˜ μ½”λ“œλ₯Ό μ“°λŠ” 것 λ§ŒμœΌλ‘œλ„ μ›ν•˜λŠ” 만큼 λ§Žμ€ μ’…λ₯˜μ˜ Vehicle을 λ§Œλ“€ 수 μžˆλ‹€.

ν•˜μ§€λ§Œ, 이 λ°©λ²•μ—λŠ” λͺ‡κ°€μ§€ λ¬Έμ œκ°€ μ‘΄μž¬ν•œλ‹€.

μš°λ¦¬κ°€ new Vehicle() μ“°κ²Œλ˜λ©΄, Javascript 엔진은 두 Vehicle 객체의 각각에 λŒ€ν•œ μƒμ„±μž ν•¨μˆ˜μ˜ 볡사본을 λ§Œλ“ λ‹€. 각 속성과 λ©”μ„œλ“œλŠ” μƒˆ Vehicle μΈμŠ€ν„΄μŠ€λ‘œ λ³΅μ‚¬λœλ‹€. 근데 λ¬Έμ œκ°€ λ­˜κΉŒμš”?

μ—¬κΈ°μ„œ λ¬Έμ œλŠ” μƒμ„±μž ν•¨μˆ˜μ˜ 멀버 ν•¨μˆ˜(λ©”μ„œλ“œ)κ°€ λͺ¨λ“  객체에 λ‚˜νƒ€λ‚˜λŠ” 것을 μ›μΉ˜ μ•ŠλŠ”λ‹€λŠ” 것이닀.. 또 λ‹€λ₯Έ λ¬Έμ œλŠ” λ‹€μŒκ³Ό 같은 κΈ°μ‘΄ 객체에 μƒˆλ‘œμš΄ μ†μ„±μ΄λ‚˜ λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•  수 μ—†λ‹€λŠ” 것이닀. :

car2.year = "2012"

이 year 속성을 μΆ”κ°€ν•˜λ €λ©΄ ν•΄λ‹Ή 속성을 μƒμ„±μž ν•¨μˆ˜ μžμ²΄μ— μΆ”κ°€ν•΄μ•Όν•œλ‹€.

function Vehicle(make, model, color, year) {
  this.make = make
  this.model = model
  this.color = color
  this.year = year
  this.getName = function() {
    return this.make + " " + this.model;
  }
}

2. Prototype

Javascriptμ—μ„œ μƒˆλ‘œμš΄ ν•¨μˆ˜κ°€ 생성될 λ•Œ λ§ˆλ‹€, Javascript 엔진은 기본적으둜 prototype 속성을 μΆ”κ°€ν•œλ‹€. prototype 속성은 객체이며 이λ₯Ό "ν”„λ‘œν† νƒ€μž… 객체"라고 λΆ€λ₯Έλ‹€. 기본적으둜 이 ν”„λ‘œν† νƒ€μž… κ°μ²΄λŠ” ν•¨μˆ˜λ₯Ό κ°€λ₯΄ν‚€λŠ” constructor 속성을 가지고 있으며, 또 λ‹€λ₯Έ 속성인 __proto__λŠ” 객체이닀. μ•„λž˜ μ˜ˆμ‹œλ₯Ό 보자.

/resource/yongkwan/14/01.png

__proto__ 속성은 "dunder proto"라고 뢈리며, μƒμ„±μž ν•¨μˆ˜μ˜ ν”„λ‘œν† νƒ€μž… 속성을 가리킀고 μžˆλ‹€.

dunderλŠ” λ‘κ°œμ˜ under bar둜 묢인 λ³€μˆ˜ 이름을 dunder properties라고 λΆ€λ₯΄λŠ” pythonμ—μ„œ μœ λž˜ν•œλ‹€.

μƒμ„±μž ν•¨μˆ˜μ˜ μƒˆ μΈμŠ€ν„΄μŠ€κ°€ 생성될 λ•Œλ§ˆλ‹€ __proto__ 속성은 은 λ‹€λ₯Έ 속성 및 λ©”μ†Œλ“œμ™€ ν•¨κ»˜ μΈμŠ€ν„΄μŠ€μ— λ³΅μ‚¬λœλ‹€.

/resource/yongkwan/14/02.png

이제 이 ν”„λ‘œν† νƒ€μž… 객체λ₯Ό μ‚¬μš©ν•˜μ—¬ μ•„λž˜μ™€ 같이 μƒˆλ‘œμš΄ 속성 및 λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•  수 있으며, μƒμ„±μž ν•¨μˆ˜μ˜ λͺ¨λ“  μΈμŠ€ν„΄μŠ€μ—μ„œ μ‚¬μš©ν•  수 μžˆλ‹€.

car.prototype.year = "2016";

ν”„λ‘œν† νƒ€μž…μ€ λ©‹μ§€μ§€λ§Œ, ν”„λ‘œν† νƒ€μž… 접근법을 μ‚¬μš©ν•˜λ©΄μ„œ μ£Όμ˜ν•΄μ•Ό ν•  점이 λͺ‡κ°€μ§€ μžˆλ‹€. ν”„λ‘œν† νƒ€μž… 속성과 λ©”μ†Œλ“œλŠ” λͺ¨λ“  μƒμ„±μž ν•¨μˆ˜μ˜ μΈμŠ€ν„΄μŠ€κ°„μ— κ³΅μœ λ˜μ§€λ§Œ, μƒμ„±μž ν•¨μˆ˜μ˜ μΈμŠ€ν„΄μŠ€ 쀑 ν•˜λ‚˜λΌλ„ μ›μ‹œ 속성을 λ³€κ²½ν•˜λ©΄, κ·Έ μΈμŠ€ν„΄μŠ€μ—λ§Œ 적용되고 λ‹€λ₯Έ μΈμŠ€ν„΄μŠ€μ—λŠ” λ°˜μ˜λ˜μ§€ μ•ŠλŠ”λ‹€.

/resource/yongkwan/14/03.png

또 λ‹€λ₯Έ ν•œκ°€μ§€λŠ” λ°°μ—΄κ³Ό 같은 μ°Έμ‘° νƒ€μž… 속성이 λͺ¨λ“  μΈμŠ€ν„΄μŠ€κ°„μ— 항상 곡유 λœλ‹€λŠ” 것이닀. μƒμ„±μž ν•¨μˆ˜μ˜ ν•œ μΈμŠ€ν„΄μŠ€κ°€ μ°Έμ‘° νƒ€μž… 속성을 μˆ˜μ •ν•˜λ©΄ λͺ¨λ“  μΈμŠ€ν„΄μŠ€κ°€ λ³€κ²½λœλ‹€.

/resource/yongkwan/14/04.png

ν”„λ‘œν† νƒ€μž…μ— κ΄€ν•œ 맀우 ν₯λ―Έλ‘­κ³  μžμ„Έν•œ κΈ°μ‚¬λŠ” μ—¬κΈ°μ—μ„œ 확인할 수 μžˆλ‹€.

3. 클래슀

μƒμ„±μž ν•¨μˆ˜μ™€ ν”„λ‘œνƒ€μž…μ„ μ΄ν•΄ν–ˆμœΌλ©΄, 이제 클래슀λ₯Ό μ΄ν•΄ν•˜κΈ° 쉽닀. μ™œλƒν•˜λ©΄ Javascript ν΄λž˜μŠ€λŠ” ν”„λ‘œν† νƒ€μž…μ„ μ΄μš©ν•˜μ—¬ μƒμ„±μž ν•¨μˆ˜λ₯Ό μ“°λŠ” μƒˆλ‘œμš΄ 방법에 λΆˆκ³Όν•˜κΈ° λ•Œλ¬Έμ΄λ‹€. μ•„λž˜μ˜ 예λ₯Ό 보자:

class Vehicle {
  constructor(make, model, color) {
    this.make = make
    this.model = model
    this.color = color
  }
  getName() {
    return this.make + " " + this.model
  }
}

Vehicle 클래슀의 μƒˆλ‘œμš΄ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜κΈ° μœ„ν•΄ μ•„λž˜μ™€ 같이 ν•΄λ³΄μž:

let car = new Vehicle("Toyota", "Corolla", "Black");

이 예제λ₯Ό μ²˜μŒμ— μƒμ„±μž ν•¨μˆ˜λ₯Ό μ„€λͺ…ν•˜λ©΄μ„œ ν–ˆλ˜ 것과 비ꡐλ₯Ό ν•΄ 보면 μ•„μ£Ό λΉ„μŠ·ν•˜λ‹€.

즉 μœ„μ— μž‘μ„±ν•œ μ½”λ“œλŠ” μ•„λž˜μ˜ μ½”λ“œμ™€ κ°™λ‹€.

function Vehicle(make, model, color) {
  this.make = make
  this.model = model
  this.color = color
}

Vehicle.prototype.getName = function() {
  return this.make + " " + this.model
}

let car = new Vehicle("Toyota", "Corolla", "Black");

λ”°λΌμ„œ ν΄λž˜μŠ€κ°€ μƒμ„±μž ν•¨μˆ˜λ₯Ό μˆ˜ν–‰ν•˜λŠ” μƒˆλ‘œμš΄ λ°©λ²•μ΄λΌλŠ” 것을 증λͺ…ν•œλ‹€. ν•˜μ§€λ§Œ μ‹€μ œ 클래슀처럼 λ§Œλ“€κΈ°μœ„ν•΄ μƒˆλ‘œμ΄ λ„μž… 된 λͺ‡κ°€μ§€μ˜ μƒˆλ‘œμš΄ 것듀과 κ·œμΉ™μ΄ μžˆλ‹€.

  1. 클래슀의 constructorλŠ” λ™μž‘ν•˜κΈ° μœ„ν•΄ new ν‚€μ›Œλ“œκ°€ ν•„μš”ν•˜λ‹€. constructorλŠ” μš°λ¦¬κ°€ μ•„λž˜μ²˜λŸΌ ν˜ΈμΆœν•  κ²½μš°μ—λ§Œ λ™μž‘ν•˜λŠ” 것을 μ˜λ―Έν•œλ‹€.
let car = new Vehicle("Toyota", "Corolla", "Black");

κ·ΈλŸ¬λ‚˜ μƒμ„±μž ν•¨μˆ˜μ—μ„  new ν‚€μ›Œλ“œ 없이 ν•¨μˆ˜μ²˜λŸΌ μ‚¬μš©ν•  수 μžˆλ‹€.

/resource/yongkwan/14/05.png

클래슀 λ³€μˆ˜λŠ” μœ„μ™€ 같이 μΈμŠ€ν„΄μŠ€ν™” ν•˜λ €κ³  ν•˜λ©΄ λ‹€μŒκ³Ό 같이 μ—λŸ¬λ₯Ό λ°œμƒν•œλ‹€.

/resource/yongkwan/14/06.png

  1. 클래슀 λ©”μ†Œλ“œλŠ” μ—΄κ±°κ°€ λΆˆκ°€λŠ₯ν•˜λ‹€.(non-enumerable) Javascriptμ—μ„œ 객체의 각 μ†μ„±μ—λŠ” enumerable ν”Œλž˜κ·Έκ°€ μ‘΄μž¬ν•œλ‹€. 이 ν”Œλž˜κ·ΈλŠ” ν•΄λ‹Ή μ†μ„±μ—μ„œ μˆ˜ν–‰ν•  일뢀 μž‘μ—…μ— λŒ€ν•œ κ°€μš©μ„±μ„ μ •μ˜ν•œλ‹€. ν΄λž˜μŠ€μ—μ„œλŠ” prototype에 μ •μ˜λœ λͺ¨λ“  λ©”μ†Œλ“œμ— λŒ€ν•΄ 이 ν”Œλž˜κ·Έλ₯Ό false둜 μ„€μ •ν•œλ‹€.

  2. ν΄λž˜μŠ€μ— constructorλ₯Ό μΆ”κ°€ν•˜μ§€ μ•ŠμœΌλ©΄, λ‹€μŒκ³Ό 같이 기본으둜 빈 constructorκ°€ μžλ™μ μœΌλ‘œ μΆ”κ°€λœλ‹€.

constructor() {}
  1. 클래슀 μ•ˆμ˜ μ½”λ“œλŠ” 항상 strict λͺ¨λ“œμ΄λ‹€. 이것은 였λ₯˜κ°€ μ—†λŠ” μ½”λ“œλ₯Ό μž‘μ„±ν•˜κ±°λ‚˜, 잘λͺ»λœ μž…λ ₯ λ˜λŠ” μ½”λ“œ μž‘μ„± 쀑에 μž‘μ„±λœ ꡬ문 였λ₯˜, λ‹€λ₯Έ κ³³μ—μ„œ μ°Έμ‘° 된 μ½”λ“œλ₯Ό μ‹€μˆ˜λ‘œ μ œκ±°ν•˜λŠ” 것을 방지해 μ€€λ‹€.

  2. 클래슀 선언은 ν˜Έμ΄μŠ€νŒ… λ˜μ§€ μ•ŠλŠ”λ‹€. Javascriptμ—μ„œ ν˜Έμ΄μŠ€νŒ…μ€ λͺ¨λ“  선언이 ν˜„μž¬ μŠ€μ½”ν”„ μœ„μ— μžλ™μœΌλ‘œ μ΄λ™ν•˜λŠ” λ©”μ»€λ‹ˆμ¦˜μ΄λ‹€. ν˜Έμ΄μŠ€νŒ…μ€ λ³€μˆ˜ λ˜λŠ” ν•¨μˆ˜κ°€ μ„ μ–Έλ˜κΈ° 전에 μ‚¬μš©ν•  수 있게 ν•œλ‹€.

κ·Έλž˜μ„œ 클래슀 선언은 ν˜Έμ΄μŠ€νŒ… λ˜μ§€ μ•ŠκΈ°μ—, 클래슀λ₯Ό μ„ μ–Έν•˜κΈ° μ „μ—λŠ” μ‚¬μš©ν•  수 μ—†λ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€. λ§Œμ•½ μ‚¬μš©ν•˜λ €κ³  μ •μ˜λ˜μ§€ μ•Šμ€ μ—λŸ¬λ₯Ό λ¦¬ν„΄ν•œλ‹€.

μ•„λž˜λŠ” λ™μž‘ν•œλ‹€.

/resource/yongkwan/14/07.png

ν•˜μ§€λ§Œ μ•„λž˜λŠ” λ™μž‘ν•˜μ§€ μ•ŠλŠ”λ‹€.

/resource/yongkwan/14/08.png

  1. ν΄λž˜μŠ€λŠ” μƒμ„±μž ν•¨μˆ˜λ‚˜ 객체 λ¦¬ν„°λŸ΄κ³Ό 같은 속성에 μ ‘κ·Όν•΄μ„œ 값을 ν• λ‹Ήν•˜λŠ” 것을 ν—ˆμš©ν•˜μ§€ μ•ŠλŠ”λ‹€. 였직 ν•¨μˆ˜λ‚˜ getter / setter둜만 κ°€λŠ₯ν•˜λ‹€. λ”°λΌμ„œ ν΄λž˜μŠ€μ—” property:value 직접 ν• λ‹Ή 값이 μ—†λ‹€.

4. 클래슀의 νŠΉμ§•

1. Constructor

μƒμ„±μžλŠ” 클래슀 μ„ μ–Έμ—μ„œ 클래슀 κ·Έ μžμ‹ μ„ λ‚˜νƒ€λ‚΄λŠ” νŠΉλ³„ν•œ ν•¨μˆ˜μ΄λ‹€. 클래슀 μΈμŠ€ν„΄μŠ€λ₯Ό μƒˆλ‘œ λ§Œλ“€λ©΄ μƒμ„±μžκ°€ μžλ™μœΌλ‘œ ν˜ΈμΆœλœλ‹€.

let car = new Vehicle("Honda", "Accord", "Purple");

μƒμ„±μžλŠ” super ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λΆ€λͺ¨ μƒμ„±μžλ₯Ό 호좜 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

ν΄λž˜μŠ€λŠ” 였직 1개의 μƒμ„±μžλ§Œ κ°€μ§ˆ 수 μžˆλ‹€.

2. Static Methods

정적 λ©”μ†Œλ“œλŠ” ν”„λ‘œν† νƒ€μž…μ— μ •μ˜ 된 클래슀의 λ‹€λ₯Έ λ©”μ†Œλ“œμ™€ 달리 ν”„λ‘œν† νƒ€μž…μ΄ μ•„λ‹Œ 클래슀 자체의 ν•¨μˆ˜μ΄λ‹€.

정적 λ©”μ„œλ“œλŠ” static ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ„ μ–Έλ˜λ©°, 주둜 μœ ν‹Έλ¦¬ν‹° ν•¨μˆ˜λ₯Ό λ§Œλ“œλŠ” 데 μ‚¬μš©λœλ‹€. 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€μ§€ μ•Šκ³  호좜 ν• μˆ˜ μžˆλ‹€. μ•„λž˜ 예λ₯Ό 보자.

class Vehicle {
  constructor(make, model, color) {
    this.make = make
    this.model = model
    this.color = color
  }
  getName() { 
    return this.make + " " + this.model
  } 
  static getColor(v) { 
    return v.color
  }
}

let car = new Vehicle("Honda", "Accord", "Purple");

Vehicle.getColor(car); // "purple"

클래슀 μΈμŠ€ν„΄μŠ€μ—μ„œ 정적 λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•  수 μ—†λ‹€λŠ” 점을 κΈ°μ–΅ν•˜λΌ.

3. Getters/Setters

ν΄λž˜μŠ€μ—μ„  μ•„λž˜μ²˜λŸΌ μ†μ„±μ˜ 값을 κ°€μ Έμ˜€κ±°λ‚˜, μ„€μ •ν•˜κΈ° μœ„ν•œ getters/settersλ₯Ό κ°€μ§ˆ 수 μžˆλ‹€.

class Vehicle {
  constructor(model) {
    this.model = model
  }
  get model() {
    return this._model
  }
  set model(value) {
    this._model = value
  }
}

λ‚΄λΆ€μ μœΌλ‘ , getters/settersλŠ” 클래슀의 prototype에 μ •μ˜λ˜μ–΄ μžˆλ‹€.

4. 상속

Javascript의 클래슀λ₯Ό μƒμ†ν•˜μ—¬ κ΅¬ν˜„ν•  수 μžˆλ‹€. extendsλ₯Ό μ‚¬μš©ν•˜λ©΄ 클래슀의 μžμ‹ 클래슀λ₯Ό λ§Œλ“€ 수 μžˆλ‹€.

예λ₯Ό λ“€μ–΄ 보자.

class Vehicle {
  constructor(make, model, color) {
    this.make = make
    this.model = model
    this.color = color
  }
  getName() {
    return this.make + " " + this.model
  }
} 
class Car extends Vehicle{ 
  getName(){
    return this.make + " " + this.model +" in child class."
  }
} 

let car = new Car("Honda", "Accord", "Purple");

car.getName(); // "Honda Accord in child class."

getName() λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ μžμ‹ ν΄λž˜μŠ€μ— μžˆλŠ” λ©”μ†Œλ“œκ°€ 호좜 된 것을 λ³Ό 수 μžˆλ‹€.

λ•Œλ‘œλŠ” λΆ€λͺ¨ 클래슀의 λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•΄μ•Όν•œλ‹€. μžμ‹ 클래슀의 λ©”μ†Œλ“œλ‚΄μ—μ„œ λΆ€λͺ¨ 클래슀의 λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜κΈ° μœ„ν•΄ super ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•œλ‹€.

getName() λ©”μ†Œλ“œλ₯Ό μ•„λž˜μ™€ 같이 λ°”κΏ” 보자.

class Car extends Vehicle{
  getName(){
    return super.getName() +" - called base class function from child class."
  }
}

이제 getName()을 μΈμŠ€ν„΄μŠ€μ—μ„œ ν˜ΈμΆœν•˜λ©΄ κ²°κ³Όκ°€ μ•„λž˜μ™€ 같이 λ°˜ν™˜λœλ‹€.

/resource/yongkwan/14/09.png

결둠적으둜 Javascript의 클래슀 λ‚΄λΆ€μ˜ κ°œλ…μ„ μ„€λͺ…ν•˜λ €κ³  ν–ˆμœΌλ©°, κ²°κ΅­μ—λŠ” 클래슀의 λͺ‡κ°€μ§€μ˜ νŠΉμ§•μ— λŒ€ν•΄ λ°°μ› λ‹€.

이 μ£Όμ œμ™€ κ΄€λ ¨ν•˜μ—¬ 더 μžμ„Έν•œ 것을 보고 μ‹ΆμœΌλ©΄ λ”°λΌμ˜€λŠ” 멋진 기사듀을 읽어라. 이뿐만 μ•„λ‹ˆλΌ, μΈν„°λ„·μ—λŠ” λ°©λŒ€ν•œ λ‹€λ₯Έ 기사듀이 λ„˜μ³λ‚œλ‹€.

References:

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
  2. http://2ality.com/2015/02/es6-classes-final.html
  3. https://javascript.info/class
  4. https://thejsguy.com/tutorials/javascript-constructor-functions-and-classes
  5. https://www.phpied.com/3-ways-to-define-a-javascript-class/