πŸ‘¨β€πŸ‘§ μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ 클래슀

thumb_hyeokΒ·2022λ…„ 3μ›” 27일
1

🟑 JavaScript

λͺ©λ‘ 보기
7/15
post-thumbnail

πŸ€” ν΄λž˜μŠ€λž€ λ¬΄μ—‡μΌκΉŒ?

μš°λ¦¬λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ ν”„λ‘œν† νƒ€μž… κΈ€μ—μ„œ 객체지ν–₯이 무엇인지 κ³΅λΆ€ν–ˆλ‹€. λ‹€μ‹œ 읽고 였기 싫은 μ‚¬λžŒλ“€μ„ μœ„ν•΄ μš”μ•½ν•˜λ©΄ 객체지ν–₯μ΄λž€, 독립적인 κ°μ²΄λ“€μ˜ μ§‘ν•©μœΌλ‘œ ν”„λ‘œκ·Έλž¨μ„ ν‘œν˜„ν•˜λ €λŠ” ν”„λ‘œκ·Έλž˜λ° νŒ¨λŸ¬λ‹€μž„μ΄λ‹€.
μ—¬κΈ°μ„œ ν΄λž˜μŠ€λŠ” 객체λ₯Ό 생성할 수 μžˆλŠ” 좔상적인 λŒ€μƒ ν˜Ήμ€ ꡬ체적인 객체λ₯Ό μ˜λ―Έν•œλ‹€. (μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ ν΄λž˜μŠ€λŠ” 객체λ₯Ό μƒμ„±ν•˜κΈ° μœ„ν•œ 틀이 λ˜λƒ, 본인 슀슀둜 ν•˜λ‚˜μ˜ 객체둜 μž‘λ™ν•˜λƒμ— λ”°λΌμ„œ 좔상적인 λŒ€μƒλ„ ꡬ체적인 객체도 될 수 μžˆλ‹€)


⏱️ ES6 μ΄μ „μ˜ 클래슀 흉내내기

ES5κΉŒμ§€λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈμ— classκ°€ μ§€μ›λ˜μ§€ μ•Šμ•˜λ‹€. κ·ΈλŸ¬λ‚˜ 클래슀 기반 객체지ν–₯ μ–Έμ–΄λ₯Ό μ‚¬μš©ν•˜λ˜ μˆ˜λ§Žμ€ μ‚¬λžŒλ“€μ΄ μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ ν”„λ‘œν† νƒ€μž…μ„ μ΄μš©ν•΄ classλ₯Ό 흉내내보렀고 μ‹œλ„ν•΄μ™”λ‹€. ν•˜μ§€λ§Œ classκ°€ 이미 λ‚˜μ˜¨ μ‹œμ μΈ μ§€κΈˆ, 이 과정을 μžμ„Ένžˆ μ‚΄νŽ΄λ³Ό ν•„μš”λŠ” 없을 것 κ°™μ•„ classλ₯Ό ν‰λ‚΄λ‚΄λŠ”λ° μžˆμ–΄ 핡심적인 μ ‘κ·Ό 방법과 μ˜ˆμ‹œν•˜λ‚˜ μ •λ„λ§Œ 보여주렀고 ν•œλ‹€.

μ ‘κ·Ό 방법

μ—¬λŸ¬ 가지 방법듀이 μžˆμ—ˆμ§€λ§Œ, μ ‘κ·Ό 방법은 μ•„λž˜μ™€ 거의 λ™μΌν•˜λ‹€.

  1. SubClass.prototype.__proto__κ°€ SuperClass.prototype을 μ°Έμ‘°ν•˜κ²Œ ν•œλ‹€.
  2. SubClass.prototype에 λΆˆν•„μš”ν•œ μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°κ°€ λ‚¨μ•„μžˆμ§€ μ•Šκ²Œ ν•œλ‹€.
  3. SubClass.prototype.constructorλ₯Ό SubClass둜 μž¬μ„€μ •ν•΄μ€€λ‹€.

μ˜ˆμ‹œ

이 κΈ€μ—μ„œλŠ” 일반적인 OOP(Object-Oriented Programming)λ°©μ‹μœΌλ‘œ ν”„λ‘œν† νƒ€μž…μ„ 클래슀처럼 μ΄μš©ν•œ μ½”λ“œμ™€ YOU DON'T KNOW JS의 μ €μž, 카일 μ‹¬μŠ¨μ΄ 지ν–₯ν•˜λŠ” OLOO(Object Linked Other Object)방식을 μ‚¬μš©ν•œ μ½”λ“œ 두 가지λ₯Ό 보여주도둝 ν•˜κ² λ‹€. λ‘˜ λ‹€ μ΄λŸ°μ‹μœΌλ‘œ 클래슀λ₯Ό 흉내 λƒˆκ΅¬λ‚˜~ μ •λ„λ‘œλ§Œ 받아듀이고 λ„ˆλ¬΄ 깊게 νŒŒκ³ λ“€μ§€ μ•Šμ•˜μœΌλ©΄ μ’‹κ² λ‹€. 이 글은 "μ–΄λ– ν•œ μ½”λ“œ μŠ€νƒ€μΌμ„ 지ν–₯ν•΄μ•Όν•˜λŠ”κ°€"κ°€ μ•„λ‹Œ "μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ 기초 κ°œλ…"을 λ‹€λ£¨λŠ” κΈ€μž„μ„ μžŠμ§€ 말자.

// 고전적인 ν”„λ‘œν† νƒ€μž… OOP μŠ€νƒ€μΌ
function Animal() {}

Animal.prototype.eat = function() {
  return 'eat';
};
Animal.prototype.sleep = function() {
  return 'sleep';
};

function Bird() {}

Bird.prototype = Object.create(Animal.prototype);
// Object.setPrototypeOf(Bird.prototype, Animal.prototype); 
// ES6λΆ€ν„° ν”„ν† ν† νƒ€μž…μ„ ꡐ체할 수 μžˆλŠ” λ‹€λ₯Έ 방법이닀.

// μ—¬κΈ°μ„œλŠ” ν•˜μ§€ μ•Šμ•˜μ§€λ§Œ μ›λž˜ constructor도 Bird둜 ꡐ체해쀀닀

Bird.prototype.fly = function() {
  return 'fly'
};

const eagle = new Bird();
console.log(eagle.fly(), eagle.eat(), eagle.sleep());
//fly eat sleep

//YOU DON'T KNOW JS의 카일 μ‹¬μŠ¨μ˜ OLOO μŠ€νƒ€μΌ
const Animal = {
  eat() {
    return 'eat';
  },
  sleep() {
    return 'sleep';
  },
};

const Bird = {
  fly() {
    return 'fly';
  },
};

Object.setPrototypeOf(Bird, Animal);
const eagle = Object.create(Bird);

console.log(eagle.fly(), eagle.eat(), eagle.sleep());

(OOPλ°©μ‹μ—μ„œλŠ” Object.prototype λ“±λ“± κ°μ²΄μ™€μ˜ 직접적인 관계가 μ•„λ‹Œκ±΄ 그림이 λ³΅μž‘ν•΄μ Έμ„œ 뺐닀)

μœ„ κΈ€μ—μ„œλŠ” μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ κΈ°λ³Έκ°œλ…μ„ λ‹€λ£¨λŠ”κ²Œ λͺ©μ μ΄κΈ° λ•Œλ¬Έμ— μœ„μ—μ„œλ„ λ§ν–ˆλ“―μ΄ OOP방식과 OLOOλ°©μ‹μ˜ 비ꡐ 같은 λ‚΄μš©μ€ κ°„λ‹¨νžˆ μ†Œκ°œλ§Œ ν•˜κ³  마무리 ν•˜λ„λ‘ ν•˜κ² λ‹€. OLOO방식은 클래슀λ₯Ό ν‰λ‚΄λƒˆλ‹€κΈ°λ³΄λ‹€, λ³΅μž‘ν•˜κ³  문제 λ§Žμ€ 클래슀λ₯Ό μ‚¬μš©ν•˜λŠ” λŒ€μ‹  ν”„λ‘œν† νƒ€μž… 상속을 이런 μ‹μœΌλ‘œ μ‚¬μš©ν•˜μž~ λΌλŠ” μ·¨μ§€μ—μ„œ λ‚˜μ˜¨ 방식이닀.
μ•„κΉŒλ„ λ§ν–ˆμ§€λ§Œ λ„ˆλ¬΄ 깊게 λ“€μ–΄κ°€μ§€λŠ” 말자.


πŸ— μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ 클래슀

자, 그럼 이제 본격적으둜 ES6에 λ„μž…λœ ν΄λž˜μŠ€μ— λŒ€ν•΄μ„œ μ‚΄νŽ΄λ³΄μž. μš°λ¦¬λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ κ°μ²΄μ—μ„œ μ—¬λŸ¬κ°€μ§€ 객체 생성방식듀을 μ‚΄νŽ΄λ³΄μ•˜λ‹€. ν΄λž˜μŠ€λŠ” ES6μ—μ„œ λ„μž…λœ 객체 생성 방식이닀.
κ·ΈλŸ¬λ‚˜, ES6의 ν΄λž˜μŠ€λŠ” 사싀 ν•¨μˆ˜μ΄λ©° κΈ°μ‘΄ ν”„λ‘œν† νƒ€μž… 기반 νŒ¨ν„΄μ„ 클래슀 기반 νŒ¨ν„΄μ²˜λŸΌ μ‚¬μš©ν•  수 μžˆλ„λ‘ ν•˜λŠ” 문법적 섀탕(syntactic sugar)이라고 λ³Ό μˆ˜λ„ μžˆλ‹€.
μ΄μ œλΆ€ν„°λŠ” 클래슀의 문법, κΈ°λŠ₯, λ™μž‘λ°©μ‹, μƒμ„±μž ν•¨μˆ˜μ™€μ˜ 차이λ₯Ό μ€‘μ‹¬μœΌλ‘œ 클래슀λ₯Ό μ„€λͺ…ν•΄λ‚˜κ°€κ² λ‹€.

μƒμ„±μž ν•¨μˆ˜μ™€μ˜ λ™μž‘ 차이

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

ν΄λž˜μŠ€λŠ” μƒμ„±μž ν•¨μˆ˜μ™€ 맀우 μœ μ‚¬ν•˜κ²Œ λ™μž‘ν•˜μ§€λ§Œ λ‹€μŒκ³Ό 같이 λͺ‡ 가지 차이가 μžˆλ‹€.

  • ν΄λž˜μŠ€λŠ” μƒμ„±μž ν•¨μˆ˜μ™€ 달리 new μ—°μ‚°μž 없이 ν˜ΈμΆœν•˜λ©΄ μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.
  • ν΄λž˜μŠ€λŠ” μƒμ„±μž ν•¨μˆ˜μ™€ 달리 상속을 μ§€μ›ν•˜λŠ” extends와 super ν‚€μ›Œλ“œλ₯Ό μ œκ³΅ν•œλ‹€.
  • ν΄λž˜μŠ€λŠ” μƒμ„±μž ν•¨μˆ˜μ™€ 달리 let, const둜 μƒμ„±ν•œ λ³€μˆ˜μ²˜λŸΌ ν˜Έμ΄μŠ€νŒ…λœλ‹€.
  • 클래슀 λ‚΄μ˜ λͺ¨λ“  μ½”λ“œλŠ” μƒμ„±μž ν•¨μˆ˜μ™€ 달리 μ•”λ¬΅μ μœΌλ‘œ strict modeκ°€ μ§€μ •λ˜μ–΄ μ‹€ν–‰λœλ‹€.
  • 클래슀의 constructor, ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ, 정적 λ©”μ„œλ“œλŠ” λͺ¨λ‘ [[Enumerable]]의 값이 falseλ‹€

클래슀 μ •μ˜

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

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

// κΈ°λͺ… 클래슀
const Person = class MyClass = {};

ν΄λž˜μŠ€λŠ” class ν‚€μ›Œλ“œλ‘œ μ •μ˜, μΌλ°˜μ μ΄μ§„ μ•Šμ§€λ§Œ ν‘œν˜„μ‹μœΌλ‘œλ„ μ •μ˜ν•  수 μžˆλ‹€. ν‘œν˜„μ‹μœΌλ‘œ 클래슀λ₯Ό μ •μ˜ν•  수 μžˆλ‹€λŠ” 것은 ν΄λž˜μŠ€κ°€ κ°’μœΌλ‘œ μ‚¬μš©ν•  수 μžˆλŠ” 일급 κ°μ²΄λΌλŠ” 것을 μ˜λ―Έν•œλ‹€. μ•„κΉŒλ„ λ§ν–ˆμ§€λ§Œ ν΄λž˜μŠ€λŠ” ν•¨μˆ˜μ΄λ‹€. 아직 ν•¨μˆ˜μ— λŒ€ν•΄μ„œ μ„€λͺ…ν•˜μ§€ μ•Šμ•˜μ§€λ§Œ, ν•¨μˆ˜λ„ 객체이며, 객체 쀑에 일급객체이닀.

ν΄λž˜μŠ€λŠ” 일급 κ°μ²΄λ‘œμ„œ λ‹€μŒκ³Ό 같은 νŠΉμ§•μ„ κ°–λŠ”λ‹€.

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

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

class Person {
	// μƒμ„±μž
	constructor(name) {
		this.name = name;
	}

	// ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ
	sayHi() {
		console.log('Hi');
	}

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

클래슀의 ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ, 정적 λ©”μ„œλ“œλ₯Ό μ •μ˜ν•˜λŠ” 문법과 μƒμ„±μž ν•¨μˆ˜μ—μ„œ 이듀을 μƒμ„±ν•˜λŠ” 문법이 μ–΄λ–»κ²Œ λ‹€λ₯Έμ§€λŠ” 직접 찾아보도둝 ν•˜μž. μ‰½κ²Œ μ°Ύμ•„λ³Ό 수 μžˆμ„κ±°λ‹€.


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

μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈμ—μ„œ μ„€λͺ…ν–ˆλ“―이 ν˜Έμ΄μŠ€νŒ…μ€ "λ³€μˆ˜ ν˜Έμ΄μŠ€νŒ…"κ³Ό "ν•¨μˆ˜ ν˜Έμ΄μŠ€νŒ…"이 μ‘΄μž¬ν•œλ‹€. 클래슀 ν‘œν˜„μ‹μœΌλ‘œ μ •μ˜λœ ν΄λž˜μŠ€λŠ” μ„€λͺ…ν•  ν•„μš”λ„ μ—†κ³ , 클래슀 μ„ μ–Έλ¬ΈμœΌλ‘œ μ •μ˜λœ 클래슀의 ν˜Έμ΄μŠ€νŒ…μ— λŒ€ν•΄μ„œλ§Œ μ‚΄νŽ΄λ³΄μž.

λ¨Όμ €, ν΄λž˜μŠ€λŠ” ν•¨μˆ˜λ‘œ ν‰κ°€λ˜κΈ° λ•Œλ¬Έμ— 클래슀 μ„ μ–Έλ¬ΈμœΌλ‘œ μ •μ˜ν•œ ν΄λž˜μŠ€λŠ” ν•¨μˆ˜ μ„ μ–Έλ¬Έκ³Ό 같이 μ†ŒμŠ€μ½”λ“œ 평가 κ³Όμ •, 즉 λŸ°νƒ€μž„ 이전에 λ¨Όμ € ν‰κ°€λ˜μ–΄ ν•¨μˆ˜ 객체λ₯Ό μƒμ„±ν•œλ‹€. 이 λ•Œ, ν΄λž˜μŠ€κ°€ ν‰κ°€λ˜μ–΄ μƒμ„±λœ ν•¨μˆ˜ κ°μ²΄λŠ” μƒμ„±μž ν•¨μˆ˜λ‘œμ„œ ν˜ΈμΆœν•  수 μžˆλŠ” ν•¨μˆ˜, 즉 constructorλ‹€. (이 λ•Œ ν”„λ‘œν† νƒ€μž…λ„ ν•¨κ»˜ μƒμ„±λœλ‹€. ν”„λ‘œν† νƒ€μž…μ€ ν•¨μˆ˜ μ •μ˜κ°€ ν‰κ°€λ˜μ–΄ ν•¨μˆ˜ 객체λ₯Ό μƒμ„±ν•˜λŠ” μ‹œμ λ˜λ©°, ν•¨μˆ˜ 객체와 짝(pair)으둜 μ‘΄μž¬ν•œλ‹€.)

단, ν΄λž˜μŠ€λŠ” 클래슀 μ •μ˜ 이전에 μ°Έμ‘°ν•  수 μ—†λ‹€. let, const ν‚€μ›Œλ“œλ‘œ μ„ μ–Έν•œ λ³€μˆ˜μ²˜λŸΌ ν˜Έμ΄μŠ€νŒ…λ˜κΈ° λ•Œλ¬Έμ— μ„ μ–Έλ¬Έ 이전에 TDZ에 빠지기 λ•Œλ¬Έμ— ν˜Έμ΄μŠ€νŒ…μ΄ λ°œμƒν•˜μ§€ μ•ŠλŠ” κ²ƒμ²˜λŸΌ λ™μž‘ν•œλ‹€.

const Crew = '';
{
  console.log(Crew); // ReferenceError: Cannot access 'Crew' before initialization
  
  class Crew {};
}

μœ„μ²˜λŸΌ ν˜Έμ΄μŠ€νŒ…μ΄ let, const으둜 μ„ μ–Έν•œ λ³€μˆ˜ ν˜Έμ΄μŠ€νŒ…κ³Ό λ™μΌν•˜κ²Œ λ°œμƒν•œλ‹€.


λ©”μ„œλ“œ

클래슀 λͺΈμ²΄μ—λŠ” constructor, ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ, 정적 λ©”μ„œλ“œλ§Œ μ •μ˜ν•  수 μžˆλ‹€κ³  ν–ˆλ‹€. μœ„μ—μ„  클래슀λ₯Ό μ–΄λ–»κ²Œ μ •μ˜ν•˜λŠ”μ§€ μ‚΄νŽ΄λ΄€μœΌλ‹ˆ, 이제 λ‚΄λΆ€μš”μ†Œλ“€μ„ 각각 λœ―μ–΄μ„œ μ‚΄νŽ΄λ³΄μž.

constructor

constructorλŠ” μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜κ³  μ΄ˆκΈ°ν™”ν•˜κΈ° μœ„ν•œ νŠΉμˆ˜ν•œ λ©”μ„œλ“œλ‹€. μƒμ„±μž ν•¨μˆ˜μ™€ λ§ˆμ°¬κ°€μ§€λ‘œ constructor λ‚΄λΆ€μ—μ„œ this에 μΆ”κ°€ν•œ ν”„λ‘œνΌν‹°λŠ” μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°κ°€ λœλ‹€. constructor λ‚΄λΆ€μ˜ thisλŠ” μƒμ„±μž ν•¨μˆ˜μ™€ λ§ˆμ°¬κ°€μ§€λ‘œ ν΄λž˜μŠ€κ°€ 생성할 μΈμŠ€ν„΄μŠ€λ₯Ό 가리킨닀.

κ·ΈλŸ¬λ‚˜ constructorλŠ” λ‹¨μˆœν•œ λ©”μ„œλ“œκ°€ μ•„λ‹ˆλ‹€. constructorλŠ” λ©”μ„œλ“œλ‘œ ν•΄μ„λ˜λŠ” 것이 μ•„λ‹ˆλΌ ν΄λž˜μŠ€κ°€ ν‰κ°€λ˜μ–΄ μƒμ„±ν•œ ν•¨μˆ˜ 객체 μ½”λ“œμ˜ 일뢀가 λœλ‹€. λ‹€μ‹œ 말해, 클래슀 μ •μ˜κ°€ ν‰κ°€λ˜λ©΄ constructor에 기술된 λ™μž‘μ„ ν•˜λŠ” ν•¨μˆ˜ 객체가 μƒμ„±λœλ‹€.

constructorλŠ” μƒμ„±μž ν•¨μˆ˜μ™€ μœ μ‚¬ν•˜μ§€λ§Œ λͺ‡ 가지 차이가 μžˆλ‹€.

  • constructorλŠ” 클래슀 내에 μ΅œλŒ€ ν•œ 개만 μ‘΄μž¬ν•  수 μžˆλ‹€.
  • constructorλŠ” μƒλž΅ν•  수 μžˆλ‹€.
  • constructorλ₯Ό μƒλž΅ν•˜λ©΄ ν΄λž˜μŠ€μ— 빈 constructorκ°€ μ•”λ¬΅μ μœΌλ‘œ μ •μ˜λœλ‹€. constructorλ₯Ό μƒλž΅ν•œ ν΄λž˜μŠ€λŠ” 빈 constructor에 μ˜ν•΄ 빈 객체λ₯Ό μƒμ„±ν•œλ‹€.
class Person {
	constructor(name) {
		this.name = name;
	}
}

const harry = new Person('Harry');
console.log(harry); // Person {name: 'Harry'}

μΈμŠ€ν„΄μŠ€λ₯Ό 생성할 λ•Œ 클래슀 μ™ΈλΆ€μ—μ„œ μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°μ˜ μ΄ˆκΈ°κ°’μ„ μ „λ‹¬ν•˜λ €λ©΄ μœ„μ™€ 같이 constructor에 λ§€κ°œλ³€μˆ˜λ₯Ό μ„ μ–Έν•˜κ³  μΈμŠ€ν„΄μŠ€λ₯Ό 생성할 λ•Œ μ΄ˆκΈ°κ°’μ„ μ „λ‹¬ν•œλ‹€. μ΄λ•Œ μ΄ˆκΈ°κ°’μ€ constructor의 λ§€κ°œλ³€μˆ˜μ—κ²Œ μ „λ‹¬λœλ‹€.

이처럼 constructor λ‚΄μ—μ„œλŠ” μΈμŠ€ν„΄μŠ€μ˜ 생성과 λ™μ‹œμ— μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°λ₯Ό μΆ”κ°€λ₯Ό 톡해 μΈμŠ€ν„΄μŠ€μ˜ μ΄ˆκΈ°ν™”λ₯Ό μ‹€ν–‰ν•œλ‹€. 그리고 constructorλŠ” λ³„λ„μ˜ λ°˜ν™˜λ¬Έμ„ 갖지 μ•Šμ•„μ•Όν•œλ‹€. μ΄λŠ” μƒμ„±μž ν•¨μˆ˜κ°€ λ™μž‘ν•˜λŠ” 방식과 λ™μΌν•˜κ²Œ λ™μž‘ν•œλ‹€. (기얡이 μ•ˆ λ‚œλ‹€λ©΄ μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ 객체 이걸 읽고 였자)

μ—¬λ‹΄μœΌλ‘œ λ§ν•˜μžλ©΄ ν”„λ‘œν† νƒ€μž…μ— μžˆλŠ” constructor ν”„λ‘œνΌν‹°λ‚˜, ν•¨μˆ˜μ˜ λ‚΄λΆ€ λ©”μ„œλ“œ [[constructor]]μ™€λŠ” 관계가 μ—†λ‹€. ν—·κ°ˆλ¦¬μ§€ μ•Šλ„λ‘ ν•˜μž. (μ„€λ§ˆ μ € λ‘˜μ€ λͺ¨λ₯΄λŠ”건 μ•„λ‹ˆκ² μ§€..?)


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

μ•„κΉŒ μœ„μ—μ„œ ν΄λž˜μŠ€μ™€ μƒμ„±μž ν•¨μˆ˜μ˜ ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ, 정적 λ©”μ„œλ“œ μ •μ˜ λ¬Έλ²•μ˜ 차이λ₯Ό 직접 찾아보라 ν–ˆμ§€λ§Œ 사싀 μ—¬κΈ°μ„œ μ„€λͺ…ν•΄ 쀄 μ˜ˆμ •μ΄μ—ˆλ‹€. 이제 μ§„μ§œ μ–΄λ–»κ²Œ λ‹€λ₯Έμ§€ μ‚΄νŽ΄λ³΄μž.
μƒμ„±μž ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ μΈμŠ€ν„΄μŠ€λ₯Ό 생성할 λ•ŒλŠ” μ•„λž˜μ™€ 같이 λͺ…μ‹œμ μœΌλ‘œ ν”„λ‘œν† νƒ€μž…μ— λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•΄μ•Όν–ˆλ‹€. ν”„λ‘œν† νƒ€μž… 체인이 μ–΄λ–€ μ‹μœΌλ‘œ μ΄λ€„μ§€λŠ”μ§€λ₯Ό ν•œ 번 ν΄λž˜μŠ€μ™€ λΉ„κ΅ν•΄μ„œ 생각해보면 쒋을 것 κ°™λ‹€.

function Person(name) {
	this.name = name;
}

Person.prototype.sayHi = function () {
	console.log('Hi');
};

const harry = new Person('harry');
harry.sayHi(); // Hi

클래슀 λͺΈμ²΄μ—μ„œ μ •μ˜ν•œ λ©”μ„œλ“œλŠ” μƒμ„±μž ν•¨μˆ˜μ— μ˜ν•œ 객체 생성 λ°©μ‹κ³ΌλŠ” λ‹€λ₯΄κ²Œ 클래슀의 prototype ν”„λ‘œνΌν‹°μ— λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•˜μ§€ μ•Šμ•„λ„ 기본적으둜 ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œκ°€ λœλ‹€.

class Person {
	constructor(name) {
		this.name = name;
	}

	sayHi() {
		console.log('Hi!');
	}
}

const harry = new Person('Harry');
harry.sayHi(); // Hi!

ν”„λ‘œν† νƒ€μž… 체인이 μ–΄λ–€ μ‹μœΌλ‘œ μ΄λ€„μ§€λŠ”μ§€ μƒκ°ν•΄λ³΄μ•˜λŠ”κ°€? 사싀 ν”„λ‘œν† νƒ€μž… 체인은 기쑴의 λͺ¨λ“  객체 생성 방식(객체 λ¦¬ν„°λŸ΄, μƒμ„±μž ν•¨μˆ˜, Object.create λ©”μ„œλ“œ λ“±)뿐만 μ•„λ‹ˆλΌ ν΄λž˜μŠ€μ— μ˜ν•΄ μƒμ„±λœ μΈμŠ€ν„΄μŠ€μ—λ„ λ™μΌν•˜κ²Œ μ μš©λœλ‹€. μƒμ„±μž ν•¨μˆ˜μ˜ 역할을 ν΄λž˜μŠ€κ°€ ν•  뿐이닀.

κ²°κ΅­ ν΄λž˜μŠ€λŠ” μƒμ„±μž ν•¨μˆ˜μ™€ 같이 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λŠ” μƒμ„±μž ν•¨μˆ˜λΌκ³  λ³Ό 수 μžˆλ‹€. κ²°κ΅­ ν΄λž˜μŠ€λ„ μƒμ„±μž ν•¨μˆ˜μ™€ λ§ˆμ°¬κ°€μ§€λ‘œ ν”„λ‘œν† νƒ€μž… 기반의 객체 생성 λ©”μ»€λ‹ˆμ¦˜μ΄λ‹€.


정적 λ©”μ„œλ“œ

ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œλ₯Ό μ„€λͺ…ν–ˆλ˜ 방식과 λ™μΌν•˜κ²Œ μ•„λž˜ μ½”λ“œμ—μ„œ λ¨Όμ € μƒμ„±μž ν•¨μˆ˜κ³Ό 클래슀의 정적 λ©”μ„œλ“œ μ •μ˜ λ°©μ‹μ˜ 차이점을 μ•Œμ•„λ³΄λ„λ‘ ν•˜κ² λ‹€.

// μƒμ„±μž ν•¨μˆ˜μ˜ 정적 λ©”μ„œλ“œ
function Person(name) {
	this.name = name;
}

Person.sayHi = function () {
	console.log('Hi!');
}

// 클래슀의 정적 λ©”μ„œλ“œ
class Person {
	constructor(name) {
		this.name = name;
	}
	
	static sayHi() {
		console.log('Hi!');
	}
}

문법 μƒμœΌλ‘œλŠ” 이런 차이가 있고, 정적 λ©”μ„œλ“œλŠ” 클래슀, μƒμ„±μž ν•¨μˆ˜μ— λ°”μΈλ”©λœ λ©”μ„œλ“œκ°€ λœλ‹€. ν΄λž˜μŠ€λŠ” ν•¨μˆ˜ 객체둜 클래슀 μ •μ˜κ°€ ν‰κ°€λ˜λŠ” μ‹œμ μ— ν•¨μˆ˜ 객체가 λ˜λ―€λ‘œ μΈμŠ€ν„΄μŠ€μ™€ 달리 별닀λ₯Έ 생성 과정이 ν•„μš” μ—†λ‹€. 정적 λ©”μ„œλ“œλŠ” μΈμŠ€ν„΄μŠ€λ‘œ ν˜ΈμΆœν•  수 μ—†κ³ , 클래슀둜 ν˜ΈμΆœν•œλ‹€.
(ν”„λ‘œν† νƒ€μž… 체인이 μ–΄λ–»κ²Œ μ—°κ²°λ˜μ–΄μžˆλŠ”μ§€λ₯Ό μ•Œλ©΄ μ΄λŠ” μƒκ°ν•˜λ©΄ λ‹Ήμ—°ν•œ 일이닀.)


클래슀의 μΈμŠ€ν„΄μŠ€ 생성방식

μš°λ¦¬λŠ” μœ„μ—μ„œ ν΄λž˜μŠ€κ°€ 뭔지, 클래슀λ₯Ό μ–΄λ–»κ²Œ μ •μ˜ν•˜λŠ”μ§€, 클래슀 λͺΈμ²΄μ—μ„œ μ •μ˜ν•  수 μžˆλŠ” 것듀이 μ–΄λ–€ 역할듀을 ν•˜λŠ”μ§€ λͺ¨λ‘ μ•Œμ•„λ΄€λ‹€. ν΄λž˜μŠ€λŠ” 객체λ₯Ό μƒμ„±ν•˜κΈ° μœ„ν•œ λ§€μ»€λ‹ˆμ¦˜μ΄λ‹€. 이제 μš°λ¦¬λŠ” ν΄λž˜μŠ€κ°€ μ–΄λ–»κ²Œ μΈμŠ€ν„΄μŠ€(객체)λ₯Ό μƒμ„±ν•˜λŠ”μ§€ μ•Œμ•„λ³Ό 수 μžˆλ‹€. ν΄λž˜μŠ€λŠ” μ•„λž˜μ™€ 같은 μˆœμ„œλ‘œ 객체λ₯Ό μƒμ„±ν•œλ‹€.

  1. μΈμŠ€ν„΄μŠ€ 생성과 this 바인딩
  2. μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™”
  3. μΈμŠ€ν„΄μŠ€ λ°˜ν™˜

μœ„μ˜ 과정을 거쳐 클래슀의 μΈμŠ€ν„΄μŠ€κ°€ μƒμ„±λ˜λŠ”λ° μ½”λ“œλ‘œ ν•œ 번 μ‚΄νŽ΄λ³΄μž

class Person {
  constructor(name) {
	// 1. λ‚΄λΆ€ μ½”λ“œ μ‹€ν–‰ 전에, μ•”λ¬΅μ μœΌλ‘œ 빈 객체 생성
	// μΈμŠ€ν„΄μŠ€μ˜ __proto__ -> 클래슀.prototype
	// μΈμŠ€ν„΄μŠ€λŠ” this에 바인딩
	console.log(this); // Person {}
	
	// 2. this에 λ°”μΈλ”©λœ μΈμŠ€ν„΄μŠ€λ₯Ό μ΄ˆκΈ°ν™”
	this.name = name;
    
	// 3. μ™„μ„±λœ μΈμŠ€ν„΄μŠ€κ°€ λ°”μΈλ”©λœ thisλ₯Ό μ•”λ¬΅μ μœΌλ‘œ λ°˜ν™˜
	}
  
  sayHi() {
   	console.log('Hi'); 
  }
  
  static sayHello() {
   	console.log('Hello'); 
  }
}

const harry = new Person("Harry");

ν”„λ‘œν† νƒ€μž… μ²΄μΈμœΌλ‘œλŠ” μ΄λ ‡κ²Œ μ—°κ²°λœλ‹€.
이전에 μƒμ„±μž ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•΄ 객체λ₯Ό λ§Œλ“€μ—ˆμ„ λ•Œμ™€ 크게 λ‹€λ₯΄μ§€ μ•Šλ‹€.


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

μ—₯ κ°‘μžκΈ° ν”„λ‘œνΌν‹°λΌλ‹ˆ! λΌλŠ” 생각이 λ“€μ—ˆκΈ°λ₯Ό λ°”λž€λ‹€. μœ„μ—μ„œ 클래슀 λͺΈμ²΄μ—μ„œλŠ” 0개 μ΄μƒμ˜ λ©”μ„œλ“œλ§Œ μ •μ˜ν•  수 μžˆλ‹€κ³  ν–ˆλŠ”λ° κ°‘μžκΈ° ν”„λ‘œνΌν‹°κ°€ λ‚˜μ™”λ‹€λ©΄ 글을 μ œλŒ€λ‘œ 읽은 μ‚¬λžŒμ΄λΌλ©΄ 당황을 ν•΄μ•Όν•œλ‹€.
μœ„μ˜ μ„€λͺ…κ³ΌλŠ” λ‹€λ₯΄κ²Œ, constructorμ—μ„œ μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°λ₯Ό μΆ”κ°€ν•΄μ£ΌλŠ” 것외에 클래슀 λͺΈμ²΄μ—μ„œ ν”„λ‘œνΌν‹°λ₯Ό μ •μ˜ν•  수 μžˆλŠ” 방법듀이 생겼닀. 이듀에 λŒ€ν•΄μ„œ μ•Œμ•„λ³΄μž.

μ ‘κ·Όμž ν”„λ‘œνΌν‹°

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

class Person {
	constructor(firstName, lastName) {
		this.firstName = firstName;
		this.lastName = lastName;
	}
	
	// getter ν•¨μˆ˜
	get fullName() {
		return `${this.firstName} ${this.lastName}`;
	}

	// setter ν•¨μˆ˜
	set fullName(name) {
		[this.firstName, this.lastName] = name.split(' ');
	}
	// fullName은 μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ‹€.
  	// get fullName(), set fullName(name)은 각각 [[get]], [[set]]μŠ¬λ‘―μ— 바인딩될 getter, setterν•¨μˆ˜μ΄λ‹€.
}

이 λ•Œ, μ ‘κ·Όμž ν”„λ‘œνΌν‹° ν‚€λŠ” μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°μ²˜λŸΌ μ‚¬μš©λœλ‹€. μ ‘κ·Όμž ν”„λ‘œνΌν‹° ν‚€λ₯Ό ν”„λ‘œνΌν‹°μ²˜λŸΌ μ°Έμ‘°ν•˜λŠ” ν˜•μ‹μœΌλ‘œ μ‚¬μš©ν•˜λ©°, μ°Έμ‘° μ‹œμ— λ‚΄λΆ€μ μœΌλ‘œ [[get]](getter ν•¨μˆ˜), [[set]](setter ν•¨μˆ˜)κ°€ ν˜ΈμΆœλœλ‹€. 클래슀의 λ©”μ„œλ“œλŠ” 기본적으둜 ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œκ°€ λœλ‹€. λ”°λΌμ„œ 클래슀의 μ ‘κ·Όμž ν”„λ‘œνΌν‹° λ˜ν•œ μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°κ°€ μ•„λ‹Œ ν”„λ‘œν† νƒ€μž…μ˜ ν”„λ‘œνΌν‹°κ°€ λœλ‹€.


클래슀 ν•„λ“œ

클래슀 ν•„λ“œλž€, 클래슀 기반 객체지ν–₯ μ–Έμ–΄μ—μ„œ ν΄λž˜μŠ€κ°€ 생성할 μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œνΌν‹°λ₯Ό λ§ν•œλ‹€. 클래슀 λͺΈμ²΄μ— 클래슀 ν•„λ“œλ₯Ό μ •μ˜ν•  수 μžˆλŠ” 클래슀 ν•„λ“œ μ •μ˜(Class field definitions)μ œμ•ˆμ€ 아직 ECMAScript의 정식 ν‘œμ€€ 사양은 μ•„λ‹ˆμ§€λ§Œ, μ΅œμ‹  λΈŒλΌμš°μ €μ™€ Node.jsμ—μ„œλŠ” 클래슀 ν•„λ“œλ₯Ό 클래슀 λͺΈμ²΄μ— μ •μ˜ν•  수 μžˆλ‹€.

μ•„λž˜ μ½”λ“œλ₯Ό 톡해 클래슀 ν•„λ“œλ₯Ό μ–΄λ–»κ²Œ 클래슀 λͺΈμ²΄μ— μ •μ˜ν•˜λŠ”μ§€ 보자.

class Person {
	// 클래슀 ν•„λ“œμ— λ¬Έμžμ—΄μ„ ν• λ‹Ή
	name = 'Harry';

	// 클래슀 ν•„λ“œμ— ν•¨μˆ˜λ₯Ό ν• λ‹Ή
	getName = function () {
		return this.name;
	}

	// ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ (ν•¨μˆ˜λ₯Ό ν• λ‹Ήν•œ 클래슀 ν•„λ“œμ™€ ν—·κ°ˆλ¦¬μ§€ 말자)
	itIsPrototypeMethod() {
		return 'It is not Classfield';
	}
}

const harry = new Person();
console.log(harry); // Person {name: "Harry", getName: f)

클래슀λ₯Ό μ •μ˜ν•  λ•Œ '<ν”„λ‘œνΌν‹° 이름> = <κ°’>'을 써주면 κ°„λ‹¨νžˆ 클래슀 ν•„λ“œλ₯Ό λ§Œλ“€ 수 μžˆλ‹€. μœ„ μ½”λ“œμ—μ„œλŠ” 클래슀 ν•„λ“œμ— λ¬Έμžμ—΄κ³Ό ν•¨μˆ˜λ₯Ό ν• λ‹Ήν–ˆλ‹€. κ·ΈλŸ¬λ‚˜ 클래슀 ν•„λ“œμ— ν•¨μˆ˜λ₯Ό ν• λ‹Ήν•˜λ©΄ 클래슀 ν•„λ“œκ°€ μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°κ°€ 되기 λ•Œλ¬Έμ— ν•΄λ‹Ή ν•¨μˆ˜λ„ μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œκ°€ λ˜λ―€λ‘œ 클래슀 ν•„λ“œμ— ν•¨μˆ˜λ₯Ό ν• λ‹Ήν•˜λŠ” 것은 ꢌμž₯ ν•˜μ§€ μ•ŠλŠ”λ‹€.

class Person {
	constructor(name) {
		this.name = name;
	}
}

κ·ΈλŸ¬λ‚˜ μΈμŠ€ν„΄μŠ€λ₯Ό 생성할 λ•Œ 클래슀 ν•„λ“œλ₯Ό μ™ΈλΆ€μ˜ μ΄ˆκΈ°κ°’μœΌλ‘œ μ΄ˆκΈ°ν™”ν•  ν•„μš”κ°€ μžˆλ‹€λ©΄ constructorμ—μ„œ 클래슀 ν•„λ“œλ₯Ό μ΄ˆκΈ°ν™”ν•΄μ•Ό ν•œλ‹€.


private ν•„λ“œ

μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” λ‹€λ₯Έ 클래슀 기반 객체지ν–₯ μ–Έμ–΄μ—μ„œ μ§€μ›ν•˜λŠ” private, public, protected ν‚€μ›Œλ“œμ™€ 같은 μ ‘κ·Ό μ œν•œμžλ₯Ό μ§€μ›ν•˜μ§€ μ•ŠλŠ”λ‹€. 즉, 클래슀 ν•„λ“œλŠ” 기본적으둜 publicν•˜κΈ° λ•Œλ¬Έμ— 외뢀에 κ·ΈλŒ€λ‘œ λ…ΈμΆœλœλ‹€. ν•˜μ§€λ§Œ private ν•„λ“œλ₯Ό μ •μ˜ν•  수 μžˆλŠ” μƒˆλ‘œμš΄ ν‘œμ€€ 사양이 μ œμ•ˆλ˜μ–΄μžˆλ‹€. 이 μ œμ•ˆλ„ μ΅œμ‹  λΈŒλΌμš°μ €μ™€ Node.js에 이미 κ΅¬ν˜„λ˜μ–΄ μžˆλ‹€.

μ–΄λ–»κ²Œ private ν•„λ“œλ₯Ό μ •μ˜ν•˜λŠ”μ§€ μ½”λ“œλ₯Ό 톡해 μ‚΄νŽ΄λ³΄μž

class Person {
	// private ν•„λ“œλŠ” λ°˜λ“œμ‹œ constructorκ°€ μ•„λ‹Œ 클래슀 λͺΈμ²΄μ— μ •μ˜ν•΄μ•Ό ν•œλ‹€.
	#name = '';
	
	constructor(name) {
		// private ν•„λ“œ μ°Έμ‘°
		this.#name = name;
	
}

const harry = new Person('Harry');

// private ν•„λ“œ #name은 클래슀 μ™ΈλΆ€μ—μ„œ μ°Έμ‘°ν•  수 μ—†λ‹€.
console.log(harry.#name);
μ ‘κ·Ό κ°€λŠ₯μ„±publicprivate
클래슀 λ‚΄λΆ€OO
μžμ‹ 클래슀 λ‚΄λΆ€OX
클래슀 μΈμŠ€ν„΄μŠ€λ₯Ό ν†΅ν•œ μ ‘κ·ΌOX

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

class Person {
	#name = '';

	constructor(name) {
		this.#name = name;
	}

	get name() {
		return this.#name;
	}
}

const harry = new Person('Harry');
console.log(harry.name); // Harry

static ν•„λ“œ

static public, static private ν•„λ“œ, static private λ©”μ„œλ“œλ₯Ό μ •μ˜ν•  수 μžˆλŠ” μƒˆλ‘œμš΄ ν‘œμ€€ 사양인 β€œStatic class features”가 μ œμ•ˆλ˜μ–΄ μžˆλ‹€. 이 μ œμ•ˆ 쀑 static public/private ν•„λ“œλŠ” 이미 μ΅œμ‹  λΈŒλΌμš°μ €, Node.js에 이미 κ΅¬ν˜„λ˜μ–΄ μžˆλ‹€.

class MyMath {
	// static public ν•„λ“œ μ •μ˜
	static PI = 22 / 7;

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

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

console.log(math.PI); // undefined
console.log(math.increment); // undefined

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

🏠➑️🏒 클래슀의 상속에 μ˜ν•œ ν™•μž₯

μ§€κΈˆκΉŒμ§€ μš°λ¦¬λŠ” ν΄λž˜μŠ€κ°€ 뭔지, μ–΄λ–»κ²Œ μ •μ˜ν•˜κ³ , 내뢀에 뭘 μ •μ˜ν•  수 μžˆλŠ”μ§€, 클래슀의 λͺ©μ μΈ 객체(μΈμŠ€ν„΄μŠ€) μƒμ„±κΉŒμ§€ μ•Œμ•„λ΄€λ‹€. 이제 λ§ˆμ§€λ§‰μœΌλ‘œ 클래슀의 상속에 μ˜ν•œ ν™•μž₯에 λŒ€ν•΄ μ•Œμ•„λ³΄λ„λ‘ ν•˜μž.
ν΄λž˜μŠ€λŠ” μ§€κΈˆκΉŒμ§€μ˜ μƒμ„±μž ν•¨μˆ˜ λ“±μ˜ λ‹€λ₯Έ 객체 생성 방식과 λ‹€λ₯΄κ²Œ "extends"λ₯Ό ν™œμš©ν•˜μ—¬, μƒμœ„ 클래슀λ₯Ό 상속 λ°›μ•„ ν•˜μœ„ 클래슀λ₯Ό ν™•μž₯ν•  수 μžˆλ‹€. μš°λ¦¬λŠ” μ•„λž˜μ—μ„œ λ„μ‹μ—μ„œ λ‚˜μ˜€λŠ” superClass, subClass의 관계에 λŒ€ν•΄ μ‚΄νŽ΄λ³Ό μ˜ˆμ •μ΄λ‹€.

subClass와 superClass

class Animal {}

class Bird extends Animal {}

const eagle = new Bird();

μœ„ μ½”λ“œμ—μ„œ Animal이 μƒμœ„ 클래슀인 superClass이며, Animal을 상속받아 ν™•μž₯된 Birdκ°€ ν•˜μœ„ 클래슀인 subClass이닀. eagle은 μ„€λͺ…ν•  것도 μ—†μ§€λ§Œ instance이닀.
"extends" ν‚€μ›Œλ“œλŠ” superClass와 subClassκ°„μ˜ 상속 관계λ₯Ό μ„€μ •ν•œλ‹€. μœ„ 그림을 보면 ν”„λ‘œν† νƒ€μž…μ„ 톡해 subClassκ°€ superClassλ₯Ό μƒμ†λ°›μ•˜λ‹€.


[[ConstructorKind]]

ν΄λž˜μŠ€λŠ” superClass와 subClassλ₯Ό κ΅¬λΆ„ν•˜κΈ° μœ„ν•΄ [[ConstructorKind]]λΌλŠ” λ‚΄λΆ€ μŠ¬λ‘―μ„ κ°–λŠ”λ‹€. λ‹€λ₯Έ 클래슀λ₯Ό 상속받지 μ•ŠλŠ” ν΄λž˜μŠ€λŠ” [[ConstructorKind]]의 값이 "base" 이고, λ‹€λ₯Έ 클래슀λ₯Ό μƒμ†λ°›λŠ” ν΄λž˜μŠ€λŠ” [[ConstructorKind]]의 값이 "derived"이닀.


super ν‚€μ›Œλ“œ

μžλ°”μŠ€ν¬λ¦½νŠΈμ—λŠ” subClassμ—μ„œ superClassλ₯Ό κ°€λ¦¬ν‚€λŠ” "super"λΌλŠ” ν‚€μ›Œλ“œκ°€ μ‘΄μž¬ν•œλ‹€. subClass의 constructorμ—μ„œλŠ” super ν˜ΈμΆœμ„ 톡해 superClass의 constructorλ₯Ό ν˜ΈμΆœν•˜λ©°, subClass의 λ©”μ„œλ“œ λ‚΄μ—μ„œλŠ” super μ°Έμ‘°λ₯Ό 톡해 superClass의 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•  수 μžˆλ‹€.

  • super 호좜: 수퍼클래슀의 constructorλ₯Ό ν˜ΈμΆœν•œλ‹€.
  1. μ„œλΈŒν΄λž˜μŠ€μ—μ„œ constructorλ₯Ό μƒλž΅ν•˜μ§€ μ•ŠλŠ” 경우 λ°˜λ“œμ‹œ superλ₯Ό ν˜ΈμΆœν•΄μ•Όν•œλ‹€.
  2. μ„œλΈŒν΄λž˜μŠ€μ˜ constructorμ—μ„œ superλ₯Ό ν˜ΈμΆœν•˜κΈ° μ „μ—λŠ” thisλ₯Ό μ°Έμ‘°ν•  수 μ—†λ‹€.
  3. superλŠ” λ°˜λ“œμ‹œ μ„œλΈŒν΄λž˜μŠ€μ˜ constructorμ—μ„œλ§Œ ν˜ΈμΆœν•΄μ•Όν•œλ‹€.
  • super μ°Έμ‘°: 수퍼클래슀의 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•  수 μžˆλ‹€.
  1. λ©”μ„œλ“œλŠ” μžμ‹ μ„ λ°”μΈλ”©ν•˜κ³  μžˆλŠ” 객체λ₯Ό κ°€λ¦¬ν‚€λŠ” λ‚΄λΆ€ 슬둯 [[HomeObject]]λ₯Ό 가진닀.
  2. [[HomeObject]]λ₯Ό κ°€μ§€λŠ” ES6의 λ©”μ„œλ“œ μΆ•μ•½ ν‘œν˜„μœΌλ‘œ μ •μ˜λœ ν•¨μˆ˜ 만이 super μ°Έμ‘°λ₯Ό ν•  수 μžˆλ‹€.
  3. super μ°Έμ‘°λŠ” 클래슀의 μ „μœ λ¬Όμ΄ μ•„λ‹ˆλ‹€. 객체 λ¦¬ν„°λŸ΄μ—μ„œλ„ super μ°Έμ‘°λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

상속 클래슀의 μΈμŠ€ν„΄μŠ€ 생성과정

상속 관계에 μžˆλŠ” 두 ν΄λž˜μŠ€κ°€ ν˜‘λ ₯ν•˜λ©° μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λŠ” 과정은 μ’€ 더 λ³΅μž‘ν•˜λ‹€. 이에 λŒ€ν•΄ μ•Œμ•„λ³΄μž.
λ¨Όμ € [[ConstructorKind]] 값에 λ”°λΌμ„œ new μ—°μ‚°μžμ™€ ν•¨κ»˜ ν˜ΈμΆœλ˜μ—ˆμ„ λ•Œμ˜ λ™μž‘μ΄ κ΅¬λΆ„λœλ‹€.

수퍼클래슀 - μΈμŠ€ν„΄μŠ€ 생성과 this 바인딩, μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™” 및 λ°˜ν™˜
μ„œλΈŒν΄λž˜μŠ€ - super 호좜, λ°˜ν™˜λœ μΈμŠ€ν„΄μŠ€ this에 바인딩, μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™” 및 λ°˜ν™˜

class Rectangle {
  constructor(height, width) {
    // 2.수퍼클래슀의 μΈμŠ€ν„΄μŠ€ 생성과 this 바인딩
    
    // 3.수퍼클래슀의 μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™”
  	this.height = height;
    this.height = width;
    
    // μΈμŠ€ν„΄μŠ€ λ°˜ν™˜ (μ„œλΈŒν΄λž˜μŠ€λŠ” μžμ‹ μ΄ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜μ§€ μ•Šκ³  λ°˜ν™˜λœ μΈμŠ€ν„΄μŠ€λ₯Ό μ‚¬μš©ν•œλ‹€)
    // κ·ΈλŸ¬λ‚˜ new.target은 μ„œλΈŒν΄λž˜μŠ€λ₯Ό 가리킨닀.
    // 즉, μΈμŠ€ν„΄μŠ€λŠ” μ„œλΈŒν΄λž˜μŠ€κ°€ μƒμ„±ν•œ κ²ƒμœΌλ‘œ μ²˜λ¦¬λœλ‹€.
  }
  
  getArea() {
  	return this.height * this.width; 
  }
}

class Square extends Rectangle {
  constructor(width) {
    // 1.μ„œλΈŒν΄λž˜μŠ€μ˜ super 호좜
    super(width, width);
    // 4.μ„œλΈŒν΄λž˜μŠ€ constructor둜의 볡귀와 this 바인딩
    
    // 5.μ„œλΈŒν΄λž˜μŠ€μ˜ μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™” (ν•΄λ‹Ή μ½”λ“œμ—μ„œλŠ” μ—†μŒ)
    // 6.μΈμŠ€ν„΄μŠ€ λ°˜ν™˜
  }
  
  getArea() {
   	return this.width ** 2; 
  }
}

const square = new Square(4);
  1. μ„œλΈŒν΄λž˜μŠ€μ˜ super 호좜
  2. 수퍼클래슀의 μΈμŠ€ν„΄μŠ€ 생성과 this 바인딩
  3. 수퍼클래슀의 μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™”
  4. μ„œλΈŒν΄λž˜μŠ€ constructor둜의 볡귀와 this 바인딩
  5. μ„œλΈŒν΄λž˜μŠ€μ˜ μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™”
  6. μΈμŠ€ν„΄μŠ€ λ°˜ν™˜

동적 상속

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

function Base1() {}

class Base2 {}

let condition = true;

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

const derived - new Derived();

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

🧐 정리

  • ν΄λž˜μŠ€λž€, 객체λ₯Ό 생성할 수 μžˆλŠ” 좔상적인 λŒ€μƒ ν˜Ήμ€ ꡬ체적인 객체λ₯Ό μ˜λ―Έν•œλ‹€
  • 클래슀 ν˜Έμ΄μŠ€νŒ…μ€ let, constλ₯Ό μ‚¬μš©ν•œ λ³€μˆ˜μ™€ λ™μΌν•˜κ²Œ λ°œμƒν•œλ‹€.
  • 클래슀 λͺΈμ²΄μ—λŠ” constructor, ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œ, 정적 λ©”μ„œλ“œ, 클래슀 ν•„λ“œλ₯Ό μ •μ˜ν•  수 μžˆλ‹€.
  • 클래슀 상속은 extendsλ₯Ό 톡해 이뀄지며, μƒμœ„, ν•˜μœ„ ν΄λž˜μŠ€κ°€ ν˜‘λ ₯ν•˜λ©° μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•œλ‹€.

πŸ“– 참고자료

  • λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ Deep Dive
      1. 클래슀 (417p~466p)
  • μ½”μ–΄ μžλ°”μŠ€ν¬λ¦½νŠΈ
      1. 클래슀 (175p~201p)
  • YOU DON’T KNOW JS
      1. ν΄λž˜μŠ€μ™€ 객체의 ν˜Όν•© (93p~111p)
      1. μž‘λ™ μœ„μž„ (144p~173p)
    • APPENDIX A. ES6 class (402p~408p)
profile
μš°μ•„ν•œν…Œν¬μ½”μŠ€ 4κΈ° μ›Ή ν”„λ‘ νŠΈμ—”λ“œ

0개의 λŒ“κΈ€