본문으둜 κ±΄λ„ˆλ›°κΈ°

🌈 Chapter 7: 클래슀

πŸ“š ν΄λž˜μŠ€μ™€ μΈμŠ€ν„΄μŠ€μ˜ κ°œλ… 이해​

  • ν΄λž˜μŠ€λŠ” ν•˜μœ„λ‘œ 갈수둝 μƒμœ„ 클래슀의 속성을 μƒμ†ν•˜λ©΄μ„œ 더 ꡬ체적인 μš”κ±΄μ΄ μΆ”κ°€ λ˜λŠ” λ³€κ²½λœλ‹€. λ¬Όλ‘  ν•˜μœ„ ν΄λž˜μŠ€κ°€ 아무리 κ΅¬μ²΄ν™”λ˜λ”λΌλ„ 이듀을 κ²°κ΅­ 좔상적인 κ°œλ…μΌ 뿐이닀.
  • μ–΄λ–€ 클래슀의 속성을 μ§€λ‹ˆλŠ” μ‹€μ‘΄ν•˜λŠ” 개체λ₯Ό 일컬어 μΈμŠ€ν„΄μŠ€(instance)라고 ν•œλ‹€.
  • μ–΄λ–€ ν΄λž˜μŠ€μ— μ†ν•œ κ°œμ²΄λŠ” κ·Έ 클래슀의 쑰건을 λͺ¨λ‘ λ§Œμ‘±ν•˜λ―€λ‘œ κ·Έ 클래슀의 ꡬ체적인 μ˜ˆμ‹œ, 즉 μΈμŠ€ν„΄μŠ€κ°€ 될 것이닀.
  • ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄μ—μ„œμ˜ ν΄λž˜μŠ€λŠ” ν˜„μ‹€μ„Έκ³„μ—μ„œμ˜ ν΄λž˜μŠ€μ™€ λ§ˆμ°¬κ°€μ§€λ‘œ 곡톡 μš”μ†Œλ₯Ό μ§€λ‹ˆλŠ” 집단을 λΆ„λ₯˜ν•˜κΈ° μœ„ν•œ κ°œλ…μ΄λΌλŠ” μΈ‘λ©΄μ—μ„œλŠ” μΌμΉ˜ν•˜μ§€λ§Œ μΈμŠ€ν„΄μŠ€λ“€λ‘œλΆ€ν„° 곡톡점을 λ°œκ²¬ν•΄μ„œ 클래슀λ₯Ό μ •μ˜ν•˜λŠ” ν˜„μ‹€κ³Ό 달리, ν΄λž˜μŠ€κ°€ λ¨Όμ € μ •μ˜λΌμ•Όλ§Œ κ·Έλ‘œλΆ€ν„° 곡톡적인 μš”μ†Œλ₯Ό μ§€λ‹ˆλŠ” κ°œμ²΄λ“€μ„ 생성할 수 μžˆλ‹€.
  • λ‚˜μ•„κ°€ ν˜„μ‹€μ„Έκ³„μ—μ„œμ˜ ν΄λž˜μŠ€λŠ” 좔상적인 κ°œλ…μ΄μ§€λ§Œ, ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄μ—μ„œμ˜ ν΄λž˜μŠ€λŠ” μ‚¬μš©ν•˜κΈ°μ— 따라 좔상적인 λŒ€μƒμΌ μˆ˜λ„ 있고 ꡬ체적인 κ°œμ²΄κ°€ 될 μˆ˜λ„ μžˆλ‹€.

πŸ“š μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ ν΄λž˜μŠ€β€‹

  • μΈμŠ€ν„΄μŠ€μ— μƒμ†λ˜λŠ”μ§€(μΈμŠ€ν„΄μŠ€κ°€ μ°Έμ‘°ν•˜λŠ”μ§€) 여뢀에 따라 μŠ€νƒœν‹± 멀버(static member)와 μΈμŠ€ν„΄μŠ€ 멀버(instance member)둜 λ‚˜λ‰œλ‹€.
// μƒμ„±μž
var Rectangle = function (width, height) {
this.width = width;
this.height = height;
};


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

// μŠ€νƒœν‹± λ©”μ„œλ“œ
Rectangle.isRectangle = function (instance) {
return instance instanceof Rectangle &&
instance.width > 0 && instance.height > 0;
};

var rect1 = new Rectangle(3, 4);

console.log(rect1.getArea()); // 12
console.log(rect1.isRectangle(rect1)); // Error
console.log(Rectangle.isRectangle(rect1)); // true
  • ν”„λ‘œν† νƒ€μž… 객체에 ν• λ‹Ήν•œ λ©”μ„œλ“œλŠ” μΈμŠ€ν„΄μŠ€κ°€ 마치 μžμ‹ μ˜ κ²ƒμ²˜λŸΌ ν˜ΈμΆœν•  수 μžˆλ‹€κ³  ν–ˆλ‹€. κ·ΈλŸ¬λ―€λ‘œ getAreaλŠ” μ‹€μ œλ‘œλŠ” react1.__proto__.getArea에 μ ‘κ·Όν•˜λŠ”λ°, μ΄λ•Œ __proto__λ₯Ό μƒλž΅ν–ˆμœΌλ―€λ‘œ thisκ°€ rect1인 μ±„λ‘œ 싀행될 ν…Œλ‹ˆκΉŒ, κ²°κ³Όλ‘œλŠ” rect1.width * rect1.height의 계산이 λ°˜ν™˜λœλ‹€. 이처럼 μΈμŠ€ν„΄μŠ€μ—μ„œ 직접 ν˜ΈμΆœν•  수 μžˆλŠ” λ©”μ„œλ“œκ°€ λ°”λ‘œ ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œμ΄λ‹€.
  • rect1μ—μ„œ isRectangleμ΄λΌλŠ” λ©”μ„œλ“œμ— μ ‘κ·Όν•˜κ³ μž ν• λ•Œ, μš°μ„  rect1에 ν•΄λ‹Ή λ©”μ„œλ“œκ°€ μžˆλŠ”μ§€ κ²€μƒ‰ν–ˆλŠ”λ° μ—†κ³ , rect1.__proto__에도 μ—†μœΌλ©°, rect1.__proto__.__proto__ (Object.prototype)에도 μ—†λ‹€. κ²°κ΅­ undefinedλ₯Ό μ‹€ν–‰ν•˜λΌλŠ” λͺ…λ Ήμ΄λ―€λ‘œ, ν•¨μˆ˜κ°€ μ•„λ‹ˆμ–΄μ„œ μ‹€ν–‰ν•  수 μ—†λ‹€λŠ” 의미둜 Uncaught TypeErrorμ—λŸ¬κ°€ λ°œμƒν•œλ‹€. μ΄λ ‡κ²Œ μΈμŠ€ν„΄μŠ€μ—μ„œ 직접 μ ‘κ·Όν•  수 μ—†λŠ” λ©”μ„œλ“œλ₯Ό μŠ€νƒœν‹± λ©”μ„œλ“œλΌκ³  ν•œλ‹€. μŠ€νƒœν‹± λ©”μ„œλ“œλŠ” μƒμ„±μž ν•¨μˆ˜λ₯Ό this둜 ν•΄μ•Όλ§Œ ν˜ΈμΆœν•  수 μžˆλ‹€.
  • 일반적인 μ‚¬μš© 방식, 즉 ꡬ체적인 μΈμŠ€ν„΄μŠ€κ°€ μ‚¬μš©ν•  λ©”μ„œλ“œλ₯Ό μ •μ˜ν•œ ν‹€μ˜ 역할을 λ‹΄λ‹Ήν•˜λŠ” λͺ©μ μ„ κ°€μ§ˆ λ•Œμ˜ ν΄λž˜μŠ€λŠ” 좔상적인 κ°œλ…μ΄μ§€λ§Œ, 클래슀 자체λ₯Ό this둜 ν•΄μ„œ 직접 μ ‘κ·Όν•΄μ•Όλ§Œ ν•˜λŠ” μŠ€νƒœν‹± λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•  λ•Œμ˜ ν΄λž˜μŠ€λŠ” κ·Έ μžμ²΄κ°€ ν•˜λ‚˜μ˜ κ°œμ²΄λ‘œμ„œ μ·¨κΈ‰λœλ‹€.

πŸ“š 클래슀 상속​

🎈 κΈ°λ³Έ κ΅¬ν˜„β€‹

var Grade = function () {
var args = Array.prototype.slice.call(arguments);

for (var i = 0; i < args.length; i++) {
this[i] = args[i];
}

this.length = args.length;
};

Grade.prototype = [];
var g = new Grade(100, 80);
  • μœ„ μ˜ˆμ œμ—μ„œ λͺ‡κ°€μ§€ 큰 λ¬Έμ œκ°€ μžˆλ‹€. length ν”„λ‘œνΌν‹°κ°€ configurable(μ‚­μ œ κ°€λŠ₯)ν•˜λ‹€λŠ” 점과, Grade.prototype에 빈 배열을 μ°Έμ‘°μ‹œμΌ°λ‹€λŠ” 점이 κ·Έλ ‡λ‹€.
// length ν”„λ‘œνΌν‹°λ₯Ό μ‚­μ œν•œ 경우
g.push(90);
console.log(g); // Grade { 0: 100, 1: 80, 2: 90, length 3 }

delete g.length;
g.push(70);
console.log(g); // Grade { 0: 70, 1: 80, 2: 90, length 1 }
  • length ν”„λ‘œνΌν‹°λ₯Ό μ‚­μ œν•˜κ³  λ‹€μ‹œ pushλ₯Ό ν–ˆλ”λ‹ˆ, pushν•œ 값이 0번째 μΈλ±μŠ€μ— λ“€μ–΄κ°”κ³ , lengthκ°€ 1이 됐닀.
  • λ‚΄μž₯ 객체인 λ°°μ—΄ μΈμŠ€ν„΄μŠ€μ˜ length ν”„λ‘œνΌν‹°λŠ” configurable 속성이 falseλΌμ„œ μ‚­μ œκ°€ λΆˆκ°€λŠ₯ν•˜μ§€λ§Œ, Grade 클래슀의 μΈμŠ€ν„΄μŠ€λŠ” λ°°μ—΄ λ©”μ„œλ“œλ₯Ό μƒμ†ν•˜μ§€λ§Œ κΈ°λ³Έμ μœΌλ‘œλŠ” 일반 객체의 μ„±μ§ˆμ„ κ·ΈλŒ€λ‘œ μ§€λ‹ˆλ―€λ‘œ μ‚­μ œκ°€ κ°€λŠ₯ν•΄μ„œ λ¬Έμ œκ°€ λœλ‹€.
  • pushλ₯Ό ν–ˆμ„ λ•Œ 0번째 μΈλ±μŠ€μ— 70이 λ“€μ–΄κ°€κ³  lengthκ°€ λ‹€μ‹œ 1이 될 수 μžˆμ—ˆλ˜ κΉŒλ‹­μ€ λ°”λ‘œ g.__proto__, 즉 Grade.prototype이 빈 배열을 가리킀고 있기 λ•Œλ¬Έμ΄λ‹€.
  • push λͺ…령에 μ˜ν•΄ μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진이 g.lengthλ₯Ό 읽고자 ν•˜λŠ”λ° g.lengthκ°€ μ—†μœΌλ‹ˆκΉŒ ν”„λ‘œν† νƒ€μž… 체이닝을 타고 g.__proto__.lengthλ₯Ό μ½μ–΄μ˜¨ 것이닀.
// μš”μ†Œκ°€ μžˆλŠ” 배열을 prototype에 λ§€μΉ­ν•œ 경우
// ...
Grade.prototype = ['a', 'b', 'c', 'd'];
var g = new Grade(100, 80);

g.push(90);
console.log(g); // Grade { 0: 100, 1: 80, 2: 90, length: 3 }

delete g.length;
g.push(70);
console.log(g); // Grade { 0: 100, 1: 80, 2: 90, empty, 4: 70, length: 5 }
  • g.lengthκ°€ μ—†μœΌλ‹ˆκΉŒ g.__proto__.lengthλ₯Ό μ°Ύκ³ , 값이 4μ΄λ―€λ‘œ 인덱슀 4에 70을 λ„£κ³ , λ‹€μ‹œ g.length에 5λ₯Ό λΆ€μ—¬ν•˜λŠ” μˆœμ„œλ‘œ λ™μž‘ν•œλ‹€.
  • 이처럼 ν΄λž˜μŠ€μ— μžˆλŠ” 값이 μΈμŠ€ν„΄μŠ€μ˜ λ™μž‘μ— 영ν–₯을 μ£Όλ©΄ μ•ˆλœλ‹€. 이런 영ν–₯을 쀄 수 μžˆλ‹€λŠ” 사싀 μžμ²΄κ°€ 이미 클래슀의 좔상성을 ν•΄μΉ˜λŠ” 것이닀.
  • λ‹€μŒμ€ μ‚¬μš©μžκ°€ μ •μ˜ν•œ 두 클래슀 μ‚¬μ΄μ—μ„œμ˜ 상속관계λ₯Ό κ΅¬ν˜„ν•œ 것이닀.
var Rectangle = function (width, height) {
this.width = width;
this.height = height;
};

Rectangle.prototype.getArea = function () {
return this.width * this.height;
};

var rect = new Rectangle(3, 4);
console.log(rect.getArea()); // 12

var Square = function (width) {
this.width = width;
this.height = width;
};

Square.prototype.getArea = function () {
return this.width * this.width;
};

var sq = new Square(5);
console.log(sq.getArea()); // 25
  • 이제 Squareλ₯Ό Rectangle의 ν•˜μœ„ 클래슀둜 삼을 수 μžˆλ‹€. getAreaλΌλŠ” λ©”μ„œλ“œλŠ” λ™μΌν•œ λ™μž‘μ„ ν•˜λ―€λ‘œ μƒμœ„ ν΄λž˜μŠ€μ—μ„œλ§Œ μ •μ˜ν•˜κ³ , ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œλŠ” ν•΄λ‹Ή λ©”μ„œλ“œλ₯Ό μƒμ†ν•˜λ©΄μ„œ height λŒ€μ‹  widthλ₯Ό λ„£μ–΄μ£Όλ©΄ λœλ‹€.
// Rectangle을 μƒμ†ν•˜λŠ” Square 클래슀
var Square = function (width) {
Rectangle.call(this, width, width);
};
// λ©”μ„œλ“œλ₯Ό μƒμ†ν•˜κΈ° μœ„ν•΄ Square의 ν”„λ‘œν† νƒ€μž… 객체에 Rectangle의 μΈμŠ€ν„΄μŠ€λ₯Ό λΆ€μ—¬ν–ˆλ‹€.
Square.prototype = new Rectangle();
  • ν•˜μ§€λ§Œ μœ„ μ½”λ“œλ§ŒμœΌλ‘œ 클래슀 체계가 ꡬ좕됐닀고 λ³Ό 수 μ—†λŠ”λ° ν΄λž˜μŠ€μ— μžˆλŠ” 값이 μΈμŠ€ν„΄μŠ€μ— 영ν–₯을 쀄 수 μžˆλŠ” κ΅¬μ‘°λΌλŠ” λ™μΌν•œ 문제λ₯Ό 가지고 μžˆλ‹€.

chapter7-1

  • μœ„ 캑쳐의 κ΅¬μ‘°μ—μ„œ 첫 μ€„μ—μ„œ Square의 μΈμŠ€ν„΄μŠ€μž„μ„ ν‘œμ‹œν•˜κ³  있고 width와 height에 λͺ¨λ‘ 5κ°€ 잘 λ“€μ–΄μžˆλ‹€. __proto__λŠ” Rectangle의 μΈμŠ€ν„΄μŠ€μž„μ„ ν‘œμ‹œν•˜κ³  μžˆλŠ”λ°, λ°”λ‘œ μ΄μ–΄μ„œ width, height에 λͺ¨λ‘ undefinedκ°€ 할당돼 μžˆλ‹€. Square.prototype에 값이 μ‘΄μž¬ν•˜λŠ” 것이 λ¬Έμ œμ΄λ‹€. λ§Œμ•½ μž„μ˜λ‘œ Square.prototype.width에 값을 λΆ€μ—¬ν•˜κ³  sq.width의 값을 μ§€μ›Œλ²„λ¦°λ‹€λ©΄ ν”„λ‘œν† νƒ€μž… 체이닝에 μ˜ν•΄ μ—‰λš±ν•œ κ²°κ³Όκ°€ λ‚˜μ˜€κ²Œ λœλ‹€.
  • λ‚˜μ•„κ°€ constructorκ°€ μ—¬μ „νžˆ Rectangleλ₯Ό 바라보고 μžˆλŠ” 것도 λ¬Έμ œμ΄λ‹€. sq.constructor둜 μ ‘κ·Όν•˜λ©΄ ν”„λ‘œν† νƒ€μž… 체이닝을 따라 sq.__proto__.__proto__, 즉 Rectangle.prototypeμ—μ„œ 찾게 되며, μ΄λŠ” Rectangle을 가리킀고 있기 λ•Œλ¬Έμ΄λ‹€.
var rect2 = new sq.constructor(2, 3);
console.log(rect2); // Rectangle { width: 2, height: 3 }

🎈 ν΄λž˜μŠ€κ°€ ꡬ체적인 데이터λ₯Ό μ§€λ‹ˆμ§€ μ•Šκ²Œ ν•˜λŠ” 방법​

  • ν΄λž˜μŠ€κ°€ ꡬ체적인 데이터λ₯Ό μ§€λ‹ˆμ§€ μ•Šκ²Œ ν•˜λŠ” 방법은 μ—¬λŸ¬ 가지가 μžˆλŠ”λ°, κ°€μž₯ μ‰¬μš΄ 방법은 일단 λ§Œλ“€κ³  λ‚˜μ„œ ν”„λ‘œνΌν‹°λ“€μ„ 일일이 μ§€μš°κ³  λ”λŠ” μƒˆλ‘œμš΄ ν”„λ‘œνΌν‹°λ₯Ό μΆ”κ°€ν•  수 μ—†κ²Œ ν•˜λŠ” 것이닀.
delete Square.prototype.width;
delete Square.prototype.height;

Object.freeze(Square.prototype);
  • ν”„λ‘œνΌν‹°κ°€ λ§Žλ‹€λ©΄ λ°˜λ³΅μ„ μ—†μ• λŠ” λ°©λ²•μœΌλ‘œ ν•¨μˆ˜λ₯Ό λ§Œλ“€μ–΄ ν•΄κ²°ν•  수 μžˆλ‹€.
// μΈμŠ€ν„΄μŠ€ 생성 ν›„ ν”„λ‘œνΌν‹° 제거
var extendClass1 = function (SuperClass, SubClass, subMethods) {
SubClass.prototype = new SuperClass();

for (var prop in SubClass.prototype) {
if (SubClass.prototype.hasOwnProperty(prop)) {
delete SubClass.prototype[prop];
}
}

if (subMethods) {
for (var method in subMethods) {
SubClass.prototype[method] = subMethods[method];
}
}

Object.freeze(SubClass.prototype);

return SubClass;
};

var Square = extendClass1(Rectangle, function (width) {
Rectangle.call(this, width, width);
});

chapter7-2

  • 두 번째 방법은 λ”κΈ€λΌμŠ€ ν¬λ½ν¬λ“œκ°€ μ œμ‹œν•΄μ„œ λŒ€μ€‘μ μœΌλ‘œ 널리 μ•Œλ €μ§„ 방법이닀.
  • SubClass의 prototype에 직접 SuperClass의 μΈμŠ€ν„΄μŠ€λ₯Ό ν• λ‹Ήν•˜λŠ” λŒ€μ‹  μ•„λ¬΄λŸ° ν”„λ‘œνΌν‹°λ₯Ό μƒμ„±ν•˜μ§€ μ•ŠλŠ” 빈 μƒμ„±μž ν•¨μˆ˜λ₯Ό ν•˜λ‚˜ 더 λ§Œλ“€μ–΄μ„œ κ·Έ prototype의 SuperClass의 prototype을 λ°”λΌλ³΄κ²Œλ” ν•œ λ‹€μŒ, SubClass의 prototypeμ—λŠ” Bridge의 μΈμŠ€ν„΄μŠ€λ₯Ό ν• λ‹Ήν•˜κ²Œ ν•˜λŠ” 것이닀.
var Rectangle = function (width, height) {
this.width = width;
this.height = height;
};

Rectangle.prototype.getArea = function () {
return this.width * this.height;
};

var Square = function (width) {
Rectangle.call(this, width, width);
};

var Bridge = function () {};

Bridge.prototype = Rectangle.prototype;
Square.prototype = new Bridge();
Object.freeze(Square.prototype);
  • BridgeλΌλŠ” 빈 ν•¨μˆ˜λ₯Ό λ§Œλ“€κ³ , Bridge.prototype이 Rectangle.prototype을 μ°Έμ‘°ν•˜κ²Œ ν•œ λ‹€μŒ, Square.prototype에 new Bridge()둜 ν• λ‹Ήν•˜λ©΄, μΈμŠ€ν„΄μŠ€λ₯Ό μ œμ™Έν•œ ν”„λ‘œν† νƒ€μž… 체인 κ²½λ‘œμƒμ—λŠ” λ”λŠ” ꡬ체적인 데이터가 λ‚¨μ•„μžˆμ§€ μ•Šκ²Œ λœλ‹€.

chapter7-3

  • λ§ˆμ§€λ§‰μœΌλ‘œ ES5μ—μ„œ λ„μž…λœ Object.createλ₯Ό μ΄μš©ν•œ 방법이닀. 이 방법은 SubClass의 prototype의 __proto__κ°€ SuperClass의 prototype을 λ°”λΌλ³΄λ˜, SuperClass의 μΈμŠ€ν„΄μŠ€κ°€ λ˜μ§€λŠ” μ•ŠμœΌλ―€λ‘œ μ•žμ˜ 두 방법보닀 더 κ°„λ‹¨ν•˜λ©΄μ„œλ„ μ•ˆμ „ν•˜λ‹€.
// ...
Square.prototype = Object.create(Rectangle.prototype);
Object.freeze(Square.prototype);
// ...

chapter7-3

  • μœ„ μ„Έ 가지 방법 λͺ¨λ‘ κ²°κ΅­ SubClass.prototype의 __proto__κ°€ SuperClass.prototypeλ₯Ό μ°Έμ‘°ν•˜κ³ , SubClass.prototypeμ—λŠ” λΆˆν•„μš”ν•œ μΈμŠ€ν„΄μŠ€ ν”„λ‘œνΌν‹°κ°€ λ‚¨μ•„μžˆμ§€ μ•ŠμœΌλ©΄ λœλ‹€.

🎈 constructor λ³΅κ΅¬ν•˜κΈ°β€‹

  • μœ„ μ„Έ 가지 방법 λͺ¨λ‘ 기본적인 μƒμ†μ—λŠ” μ„±κ³΅ν–ˆμ§€λ§Œ SubClass μΈμŠ€ν„΄μŠ€μ˜ constructorλŠ” μ—¬μ „νžˆ SuperClassλ₯Ό κ°€λ¦¬ν‚€λŠ” μƒνƒœμ΄λ‹€. μ—„λ°€νžˆλŠ” SubClass μΈμŠ€ν„΄μŠ€μ—λŠ” constructorκ°€ μ—†κ³ , SubClass.prototype에도 μ—†λŠ” μƒνƒœμ΄λ‹€. ν”„λ‘œν† νƒ€μž… 체인상에 κ°€μž₯ λ¨Όμ € λ“±μž₯ν•˜λŠ” SuperClass.prototype의 constructorμ—μ„œ κ°€λ¦¬ν‚€λŠ” λŒ€μƒ, 즉 SuperClassκ°€ 좜λ ₯될 뽄이닀.
  • λ”°λΌμ„œ SubClass.prototype.constructorκ°€ μ›λž˜μ˜ SubClassλ₯Ό 바라보도둝 ν•΄μ£Όλ©΄ λœλ‹€.
  1. μΈμŠ€ν„΄μŠ€ 생성 ν›„ ν”„λ‘œνΌν‹° 제거
var extendClass1 = function (SuperClass, SubClass, subMethods) {
SubClass.prototype = new SuperClass();

for (var prop in SubClass.prototype) {
if (SubClass.prototype.hasOwnProperty(prop)) {
delete SubClass.prototype[prop];
}
}

SubClass.prototype.constructor = SubClass;

if (subMethods) {
for (var method in subMethods) {
SubClass.prototype[method] = subMethods[method];
}
}

Object.freeze(SubClass.prototype);

return SubClass;
};
  1. 빈 ν•¨μˆ˜λ₯Ό 이용
var extendClass2 = (function () {
var Bridge = function () {};

return function (SuperClass, SubClass, subMethods) {
Bridge.prototype = SuperClass.prototype;
SubClass.prototype = new Bridge();
SubClass.prototype.constructor = SubClass;

if (subMethods) {
for (var method in subMethods) {
SubClass.prototype[method] = subMethods[method];
}
}

Object.freeze(SubClass.prototype);

return SubClass;
};
})();
  1. Object.create ν™œμš©
var extendClass3 = function (SuperClass, SubClass, subMethods) {
SubClass.prototype = Object.create(SuperClass.prototype);
SubClass.prototype.constructor = SubClass;

if (subMethods) {
for (var method in subMethods) {
SubClass.prototype[method] = subMethods[method];
}
}

Object.freeze(SubClass.prototype);

return SubClass;
}
  • κ°€μž₯ 기본적인 κΈ°λŠ₯인 상속 및 μΆ”μƒν™”λ§ŒνΌμ€ μ„±κ³΅μ μœΌλ‘œ 달성할 수 μžˆλ‹€.

🎈 μƒμœ„ ν΄λž˜μŠ€μ—μ˜ μ ‘κ·Ό μˆ˜λ‹¨ μ œκ³΅β€‹

  • λ•Œλ‘  ν•˜μœ„ 크래슀의 λ©”μ„œλ“œμ—μ„œ μƒμœ„ 클래슀의 λ©”μ„œλ“œ μ‹€ν–‰ κ²°κ³Όλ₯Ό λ°”νƒ•μœΌλ‘œ 좔가적인 μž‘μ—…μ„ μˆ˜ν–‰ν•˜κ³  싢을 λ•Œκ°€ μžˆλ‹€. 이럴 λ•Œ 맀번 SuperClass.prototype.method.apply(this, arguments)둜 ν•΄κ²°ν•˜λŠ” 것은 μƒλ‹Ήνžˆ 번거둭고 가독성이 떨어진닀.
  • 이런 λ³„λ„μ˜ μˆ˜λ‹¨, 즉 λ‹€λ₯Έ 객체지ν–₯ μ–Έμ–΄λ“€μ˜ 클래슀 문법 쀑 ν•˜λ‚˜μΈ superλ₯Ό 흉내 λ‚΄λ³Έλ‹€.
var extendClass = function (SuperClass, SubClass, subMethods) {
SubClass.prototype = Object.create(SuperClass.prototype);
SubClass.prototype.constructor = SubClass;
SubClass.prototype.super = function (propName) {
var self = this;

// μΈμžκ°€ λΉ„μ–΄μžˆμ„ 경우
if (!propName) {
// SuperClass μƒμ„±μž ν•¨μˆ˜μ— μ ‘κ·Όν•˜λŠ” 것
return function () {
SuperClass.apply(self, arguments);
}
}

var prop = SuperClass.prototype[propName];

// ν•¨μˆ˜κ°€ 아닐 κ²½μš°μ— κ·ΈλŒ€λ‘œ λ°˜ν™˜
if (typeof prop !== 'function') {
return prop;
}

return function () {
return prop.apply(self, arguments);
}
};

if (subMethods) {
for (var method in subMethods) {
SubClass.prototype[method] = subMethods[method];
}
}

Object.freeze(SubClass.prototype);

return SubClass;
}

var Rectangle = function (width, height) {
this.width = width;
this.height = height;
};

Rectangle.prototype.getArea = function () {
return this.width * this.height;
};

var Square = extendClass(
Rectangle,
function (width) {
this.super()(width, width);
},
{
getArea: function () {
console.log('size is: ', this.super('getArea')());
}
}
);

var sq = new Square(10);
sq.getArea(); // size is: 100
console.log(sq.super('getArea')()); // 100

πŸ“š ES6의 클래슀 및 클래슀 상속​

  • ES5와 ES6의 클래슀 문법 비ꡐ
// ES5
var ES5 = function (name) {
this.name = name;
};

ES5.staticMethod = function () {
return this.name + ' staticMethod';
};

ES5.prototype.method = function () {
return this.name + ' method';
};

var es5Instance = new ES5('es5');
console.log(ES5.staticMethod()); // ES5 staticMethod
console.log(es5Instance.method()); // es5 method

// ES6
var ES6 = class {
constructor (name) {
this.name = name;
}

// μƒμ„±μž ν•¨μˆ˜μ— λ°”λ‘œ ν• λ‹Ήν•˜λŠ” λ©”μ„œλ“œμ™€ λ™μΌν•˜κ²Œ μƒμ„±μž ν•¨μˆ˜ μžμ‹ λ§Œμ΄ ν˜ΈμΆœν•  수 μžˆλ‹€.
static staticMethod () {
return this.name + ' staticMethod';
}

method () {
return this.name + ' method';
}
};

var es6Instance = new ES6('es6');
console.log(ES6.staticMethod()); // ES6 staticMethod
console.log(es6Instance.method()); // es6 method
  • λ‹€μŒμ€ 클래슀 상속이닀.
var Rectangle = class {
constructor (width, height) {
this.width = width;
this.height = height;
}

getArea () {
return this.width * this.height;
}
};

var Square = class extends Rectangle {
constructor (width) {
super(width, width);
}

getArea () {
console.log('size is: ', super.getArea());
}
}

πŸ“š 정리​

  • ν΄λž˜μŠ€λŠ” μ–΄λ–€ μ‚¬λ¬Όμ˜ 곡톡 속성을 λͺ¨μ•„ μ •μ˜ν•œ 좔상적인 κ°œλ…
  • μΈμŠ€ν„΄μŠ€λŠ” 클래슀의 속성을 μ§€λ‹Œ ꡬ체적인 사둀이닀.
  • μƒμœ„ 클래슀의 쑰건을 μΆ©μ‘±ν•˜λ©΄μ„œ λ”μš± ꡬ체적인 쑰건이 μΆ”κ°€λœ 것을 ν•˜μœ„ 클래슀라고 ν•œλ‹€.
  • 클래슀의 prototype 내뢀에 μ •μ˜λœ λ©”μ„œλ“œλ₯Ό ν”„λ‘œν† νƒ€μž… λ©”μ„œλ“œλΌκ³  ν•˜λ©°, 이듀은 μΈμŠ€ν„΄μŠ€κ°€ 마치 μžμ‹ μ˜ κ²ƒμ²˜λŸΌ ν˜ΈμΆœν•  수 μžˆλ‹€.
  • 클래슀(μƒμ„±μž ν•¨μˆ˜)에 직접 μ •μ˜ν•œ λ©”μ„œλ“œλ₯Ό μŠ€νƒœν‹± λ©”μ„œλ“œλΌκ³  ν•˜λ©°, 이듀은 μΈμŠ€ν„΄μŠ€κ°€ 직접 ν˜ΈμΆœν•  수 μ—†κ³  클래슀(μƒμ„±μž ν•¨μˆ˜)에 μ˜ν•΄μ„œλ§Œ ν˜ΈμΆœν•  수 μžˆλ‹€.
  • 클래슀 상속을 흉내 λ‚΄κΈ° μœ„ν•΄ μ„Έ 가지 방법이 μžˆλŠ”λ° SubClass.prototype에 SuperClass의 μΈμŠ€ν„΄μŠ€λ₯Ό ν• λ‹Ήν•œ λ‹€μŒ ν”„λ‘œνΌλ””λ₯Ό λͺ¨λ‘ μ‚­μ œν•˜λŠ” 방법, 빈 ν•¨μˆ˜(Bridge)λ₯Ό ν™œμš©ν•˜λŠ” 방법, Object.createλ₯Ό μ΄μš©ν•˜λŠ” 방법이닀.
  • 이 μ„Έ 방법 λͺ¨λ‘ constructor ν”„λ‘œνΌν‹°κ°€ μ›λž˜μ˜ μƒμ„±μž ν•¨μˆ˜λ₯Ό 바라보도둝 μ‘°μ •ν•΄μ•Ό ν•œλ‹€.
  • 상속 및 좔상화λ₯Ό κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄ μƒλ‹Ήνžˆ λ³΅μž‘ν•œ 방법을 μ‚¬μš©ν•΄μ•Ό ν–ˆλŠ”λ°, ES6μ—μ„œλŠ” μƒλ‹Ήνžˆ κ°„λ‹¨ν•˜κ²Œ μ²˜λ¦¬ν•  수 μžˆλ‹€.