π 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();
- νμ§λ§ μ μ½λλ§μΌλ‘ ν΄λμ€ μ²΄κ³κ° ꡬμΆλλ€κ³ λ³Ό μ μλλ° ν΄λμ€μ μλ κ°μ΄ μΈμ€ν΄μ€μ μν₯μ μ€ μ μλ ꡬ쑰λΌλ λμΌν λ¬Έμ λ₯Ό κ°μ§κ³ μλ€.
- μ μΊ‘μ³μ ꡬ쑰μμ 첫 μ€μμ
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);
});
- λ λ²μ§Έ λ°©λ²μ λκΈλΌμ€ ν¬λ½ν¬λκ° μ μν΄μ λμ€μ μΌλ‘ λ리 μλ €μ§ λ°©λ²μ΄λ€.
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()
λ‘ ν λΉνλ©΄, μΈμ€ν΄μ€λ₯Ό μ μΈν νλ‘ν νμ μ²΄μΈ κ²½λ‘μμλ λλ ꡬ체μ μΈ λ°μ΄ν°κ° λ¨μμμ§ μκ² λλ€.
- λ§μ§λ§μΌλ‘ ES5μμ λμ
λ
Object.create
λ₯Ό μ΄μ©ν λ°©λ²μ΄λ€. μ΄ λ°©λ²μSubClass
μprototype
μ__proto__
κ°SuperClass
μprototype
μ λ°λΌλ³΄λ,SuperClass
μ μΈμ€ν΄μ€κ° λμ§λ μμΌλ―λ‘ μμ λ λ°©λ²λ³΄λ€ λ κ°λ¨νλ©΄μλ μμ νλ€.
// ...
Square.prototype = Object.create(Rectangle.prototype);
Object.freeze(Square.prototype);
// ...
- μ μΈ κ°μ§ λ°©λ² λͺ¨λ κ²°κ΅
SubClass.prototype
μ__proto__
κ°SuperClass.prototype
λ₯Ό μ°Έμ‘°νκ³ ,SubClass.prototype
μλ λΆνμν μΈμ€ν΄μ€ νλ‘νΌν°κ° λ¨μμμ§ μμΌλ©΄ λλ€.
π constructor 볡ꡬνκΈ°β
- μ μΈ κ°μ§ λ°©λ² λͺ¨λ κΈ°λ³Έμ μΈ μμμλ μ±κ³΅νμ§λ§
SubClass
μΈμ€ν΄μ€μconstructor
λ μ¬μ νSuperClass
λ₯Ό κ°λ¦¬ν€λ μνμ΄λ€. μλ°νλSubClass
μΈμ€ν΄μ€μλconstructor
κ° μκ³ ,SubClass.prototype
μλ μλ μνμ΄λ€. νλ‘ν νμ 체μΈμμ κ°μ₯ λ¨Όμ λ±μ₯νλSuperClass.prototype
μconstructor
μμ κ°λ¦¬ν€λ λμ, μ¦SuperClass
κ° μΆλ ₯λ λ½μ΄λ€. - λ°λΌμ
SubClass.prototype.constructor
κ° μλμSubClass
λ₯Ό λ°λΌλ³΄λλ‘ ν΄μ£Όλ©΄ λλ€.
- μΈμ€ν΄μ€ μμ± ν νλ‘νΌν° μ κ±°
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;
};
- λΉ ν¨μλ₯Ό μ΄μ©
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;
};
})();
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