Chapter 5: Prototypes - hochan222/Everything-in-JavaScript GitHub Wiki
[Prototype](/hochan222/Everything-in-JavaScript/wiki/Prototype)
ํ๋กํ ํ์ ์ ๋จ์ํ๊ฒ ๋ค๋ฅธ ๊ฐ์ฒด์ ๋ํ ์ฐธ์กฐ์ด๋ค. ๊ฐ์ฒด์์ ์ด ์์ฑ์ด ์์ฑ๋ ๋ null์ด ์๋ ๊ฐ์ด ์ฃผ์ด์ง๋ค.
๊ธฐ๋ณธ Get ์์ ์ ๊ฐ์ฒด์์ ์์ฒญ ๋ ์์ฑ์ ์ง์ ์ฐพ์ ์์๋ ๊ฒฝ์ฐ ๊ฐ์ฒด์ Prototype ๋งํฌ๋ฅผ ๋ฐ๋ผ ์งํ๋๋ค.
var anotherObject = {
a: 2
};
// create an object linked to `anotherObject`
var myObject = Object.create( anotherObject );
myObject.a; // 2
a๊ฐ anotherObject์์ ๋ฐ๊ฒฌ๋์ง ์์ผ๋ฉด ๋น์ด์์ง ์์ ๊ฒฝ์ฐ Prototype ์ฒด์ธ์ ๋ค์ ์ฐธ์กฐํ๊ณ ์ถ์ ํ๋ค. ์ด ํ๋ก์ธ์ค๋ ์ผ์นํ๋ ์์ฑ ์ด๋ฆ์ ์ฐพ๊ฑฐ๋ Prototype ์ฒด์ธ์ด ๋๋ ๋๊น์ง ๊ณ์๋๋ค.
for in ์ ํตํด์๋ ํ์ธ ๊ฐ๋ฅํ๋ค.
var anotherObject = {
a: 2
};
// create an object linked to `anotherObject`
var myObject = Object.create( anotherObject );
for (var k in myObject) {
console.log("found: " + k);
}
// found: a
("a" in myObject); // true
Object.prototype
Prototype chain์ ์ ํํ ์ด๋์ ๋๋ ๊น?
๋ชจ๋ prototype์ ์ต์์๋ Object.prototype
์ด๋ค.
Setting & Shadowing Properties
myObject.foo = "bar";
myObject ๊ฐ์ฒด์ ์ด๋ฏธ foo๋ผ๋ ์ผ๋ฐ ๋ฐ์ดํฐ ์ ๊ทผ์ ์์ฑ์ด ์กด์ฌํ๋ ๊ฒฝ์ฐ ๊ฐ์ ํ ๋น์ ๊ธฐ์กด ์์ฑ์ ๊ฐ์ ๋ณ๊ฒฝํ๋ ๊ฒ์ฒ๋ผ ๊ฐ๋จํ๋ค. ํ์ง๋ง, foo๊ฐ myObject์ ์ง์ ์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ Get ์์ ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก Prototype ์ฒด์ธ์ด ์ํ๋๋ค. ๋ง์ฝ ๋ชป์ฐพ์ผ๋ฉด myObject์ ์ง์ ์ถ๊ฐํ๋ค.
foo๊ฐ myObject์์๋ ๋์ ๋ ๋ฒจ์ Prototype chain์์ ๋๋ ๋ ์๋์์ด๋ผ๊ณ ํ๋ค. ํญ์ ๋ฎ์ ๋ ๋ฒจ์์ ์ฐพ๊ธฐ๋๋ฌธ์ ๋์ ๋ ๋ฒจ์ ๋ชจ๋ foo ์์ฑ์ ์จ๊ฒจ์ง๋ค.
var anotherObject = {
a: 2
};
var myObject = Object.create( anotherObject );
anotherObject.a; // 2
myObject.a; // 2
anotherObject.hasOwnProperty( "a" ); // true
myObject.hasOwnProperty( "a" ); // false
myObject.a++; // oops, implicit shadowing!
anotherObject.a; // 2
myObject.a; // 3
myObject.hasOwnProperty( "a" ); // true
"Class"
์ฌ์ค ์๋ฐ ์คํฌ๋ฆฝํธ๋ "๊ฐ์ฒด ์งํฅ"์ด๋ผ๋ ๋จ์ด๋ฅผ ์ฌ์ฉํ ์ ์๋ ๋ช ์๋๋ ์ธ์ด์ผ ๊ฒ์ด๋ค. ์๋ฐ ์คํฌ๋ฆฝํธ๋ ํด๋์ค ์์ด ๊ฐ์ฒด๋ฅผ ์ง์ ์์ฑ ํ ์์๋ ๋งค์ฐ ์งง์ ์ธ์ด์ด๊ธฐ ๋๋ฌธ์ด๋ค.
"Class" Functions
๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ํจ์๋ ํ๋กํ ํ์ ์ด๋ผ๊ณ ํ๋ ์ด๊ฑฐ ํ ์์๋ ๊ณต๊ฐ ์์ฑ์ ์ป๋๋ฐ, ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฅดํจ๋ค.
function Foo() {
// ...
}
Foo.prototype; // { }
๊ฐ์ฅ ์ง์ ์ ์ธ ์ค๋ช ์ new Few()๋ก ์์ฑํ ๊ฐ์ฒด๊ฐ ์ด ํ๋กํ ํ์ ์ ์ฐ๊ฒฐ๋๋ค๋ ๊ฒ์ด๋ค.
function Foo() {
// ...
}
var a = new Foo();
Object.getPrototypeOf( a ) === Foo.prototype; // true
new Foo()๋ฅผ ํธ์ถํ์ฌ a๊ฐ ์์ฑ ๋ ๋ ๋ฐ์ํ๋ ์ผ ์ค ํ๋๋ Foo.prototype์ด ๊ฐ๋ฆฌํค๋ ๊ฐ์ฒด์ ๋ํ ๋ด๋ถ Prototype ๋งํฌ๋ฅผ ์ป๋ ๊ฒ์ด๋ค.
ํด๋์ค ์งํฅ ์ธ์ด์์๋ ์ธ์คํด์คํ ๊ณผ์ ์ด 'ํด๋น ํด๋์ค์ ํ๋ ๊ณํ์ ๋ฌผ๋ฆฌ์ ๊ฐ์ฒด๋ก ๋ณต์ฌํ๋ ๊ฒ'์ ์๋ฏธํ๋ค.
๊ทธ๋ฌ๋ ์๋ฐ์คํฌ๋ฆฝํธ์์๋ ์ด๋ฐ ๋ณต์ฌ ๊ณผ์ ์ด ์ํ๋์ง ์๋๋ค. ํด๋์ค์ ์ฌ๋ฌ ์ธ์คํด์ค๋ฅผ ๋ง๋ค์ง๋ ์๋๋ค. ๊ณตํต ๊ฐ์ฒด์ Prototype ๋งํฌํ๋ ์ฌ๋ฌ ๊ฐ์ฒด๋ฅผ ๋ง๋ ๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ๋ณต์ฌ๊ฐ ๋ฐ์ํ์ง ์๋๋ค.
์ฐ๋ฆฌ๋ ์ด๊ฒ์ "prototypal inheritance"์ด๋ผ ๋ถ๋ฅธ๋ค. ์๋ฐ์คํฌ๋ฆฝํธ๋ ๋ ๊ฐ์ฒด์ฌ์ด์ ๋งํฌ๋ฅผ ์์ฑํ๋ค. ์ฌ๊ธฐ์ ํ๋์ ๊ฐ์ฒด๋ ๋ณธ์ง์ ์ผ๋ก ๋ค๋ฅธ ๊ฐ์ฒด์ ๋ํ ์์ฑ/๊ธฐ๋ฅ ์ก์ธ์ค๋ฅผ ์์ ํ ์ ์๋ค.
"Constructors"
function Foo() {
// ...
}
var a = new Foo();
Foo๊ฐ class๋ผ๊ณ ์๊ฐํ๋ ์ด์ ๋ ๋ฌด์์ธ๊ฐ?
function Foo() {
// ...
}
Foo.prototype.constructor === Foo; // true
var a = new Foo();
a.constructor === Foo; // true
Constructor Or Call?
function NothingSpecial() {
console.log( "Don't mind me!" );
}
var a = new NothingSpecial();
// "Don't mind me!"
a; // {}
์ผ๋ฐ ํจ์ ํธ์ถ ์์ new ํค์๋๋ฅผ ๋ฃ์ผ๋ฉด ํด๋น ํจ์ ํธ์ถ์ด "์์ฑ์ ํธ์ถ"์ด ๋๋ค.
Mechanics
function Foo(name) {
this.name = name;
}
Foo.prototype.myName = function() {
return this.name;
};
var a = new Foo( "a" );
var b = new Foo( "b" );
a.myName(); // "a"
b.myName(); // "b"
"Constructor" Redux
function Foo() { /* .. */ }
Foo.prototype = { /* .. */ }; // create a new prototype object
var a1 = new Foo();
a1.constructor === Foo; // false!
a1.constructor === Object; // true!
Foo.prototype์ .constructor ์์ฑ์ ๊ธฐ๋ณธ์ ์ผ๋ก Foo ํจ์๊ฐ ์ ์ธ ๋ ๋ ์์ฑ ๋ ๊ฐ์ฒด์๋ง ์๋ค. new๋ก ์์ฑํ ๊ฐ์ฒด๋ฅผ ํจ์์ ๊ธฐ๋ณธ .prototype ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ๋์ฒดํ๋ฉด ๊ฐ์ฒด๋ ๊ธฐ๋ณธ์ ์ผ๋ก .constructor๋ฅผ ์ป์ง ์๋๋ค.
Misconception, busted.
function Foo() { /* .. */ }
Foo.prototype = { /* .. */ }; // create a new prototype object
// Need to properly "fix" the missing `.constructor`
// property on the new object serving as `Foo.prototype`.
// See Chapter 3 for `defineProperty(..)`.
Object.defineProperty( Foo.prototype, "constructor" , {
enumerable: false,
writable: true,
configurable: true,
value: Foo // point `.constructor` at `Foo`
} );
"(Prototypal) Inheritance"
function Foo(name) {
this.name = name;
}
Foo.prototype.myName = function() {
return this.name;
};
function Bar(name,label) {
Foo.call( this, name );
this.label = label;
}
// here, we make a new `Bar.prototype`
// linked to `Foo.prototype`
Bar.prototype = Object.create( Foo.prototype );
// Beware! Now `Bar.prototype.constructor` is gone,
// and might need to be manually "fixed" if you're
// in the habit of relying on such properties!
Bar.prototype.myLabel = function() {
return this.label;
};
var a = new Bar( "a", "obj a" );
a.myName(); // "a"
a.myLabel(); // "obj a"
// doesn't work like you want!
Bar.prototype = Foo.prototype;
// works kinda like you want, but with
// side-effects you probably don't want :(
Bar.prototype = new Foo();
// pre-ES6
// throws away default existing `Bar.prototype`
Bar.prototype = Object.create( Foo.prototype );
// ES6+
// modifies existing `Bar.prototype`
Object.setPrototypeOf( Bar.prototype, Foo.prototype );
Inspecting "Class" Relationships
a์ ๊ฐ์ ๊ฐ์ฒด๊ฐ ์๊ณ ์ด๋ค ๊ฐ์ฒด (์๋ ๊ฒฝ์ฐ)๋ฅผ ์์ํ๋์ง ํ์ธํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ๋?
์ ํต ํด๋ผ์ค ์งํฅ ํ๊ฒฝ์์ ์ธ์คํด์ค์ธ์ง ํ์ธํ๋ ๊ฒ์ introspection (or reflection)์ด๋ผ ํ๋ค.
function Foo() {
// ...
}
Foo.prototype.blah = ...;
var a = new Foo();
a instanceof Foo; // true
a์ ์ ์ฒด Prototype ์ฒด์ธ์์ Foo.prototype์ ์์๋ก ๊ฐ๋ฆฌํค๋ ๊ฐ์ฒด๊ฐ ์๋์ง instanceof๊ฐ ์กฐ์ฌํด์ค๋ค.
๊ทธ์๋ํ ์ค๋ํซ์ ๋ค์๊ณผ ๊ฐ๋ค.
// helper utility to see if `o1` is
// related to (delegates to) `o2`
function isRelatedTo(o1, o2) {
function F(){}
F.prototype = o2;
return o1 instanceof F;
}
var a = {};
var b = Object.create( a );
isRelatedTo( b, a ); // true
๋ฐ๋ผ์ ๋๊ฐ์ ์ธ์คํด์ค๊ฐ์๋ instanceof ๋ง์ผ๋ก๋ ๋ถ์กฑํ ์ ์๋ค.
Foo.prototype.isPrototypeOf( a ); // true
a์ ์ ์ฒด Prototype ์ฒด์ธ์์ Foo.prototype์ด ๋ํ๋๋์ง?
instanceof์ ๋์ผํ๋ค ๊ทธ๋ฌ๋ ์ ์ผํ ์ฐจ์ด์ ์ ๋ ๋ฒ์งธ ์ ๊ทผ ๋ฐฉ์์์๋ .prototype ์์ฑ์ด ์๋์ผ๋ก ์ฐธ์กฐ๋๋ ํจ์๋ฅผ ์ฐธ์กฐํ๋ ๊ฐ์ ์ ์ธ ๋ฐฉ๋ฒ์ด ํ์ํ์ง์๋๋ค.
// Simply: does `b` appear anywhere in
// `c`s [Prototype](/hochan222/Everything-in-JavaScript/wiki/Prototype) chain?
b.isPrototypeOf( c );
Object.getPrototypeOf( a ) === Foo.prototype; // true
๋๋ถ๋ถ์ ๋ธ๋ผ์ฐ์ ์ ๋ด๋ถ Prototype์ ์ก์ธ์คํ๋ ๋นํ์ค ๋์ฒด ๋ฐฉ๋ฒ๋ ์ค๋ซ๋์ ์ง์ํด ์๋ค.
a.__proto__ === Foo.prototype; // true
proto(ES6๊น์ง ํ์คํ๋์ง ์์)๋ ๊ฐ์ฒด์ ๋ด๋ถ Prototype์ ์ฐธ์กฐ๋ก ๊ฒ์ํ๋ค.
Object.defineProperty( Object.prototype, "__proto__", {
get: function() {
return Object.getPrototypeOf( this );
},
set: function(o) {
// setPrototypeOf(..) as of ES6
Object.setPrototypeOf( this, o );
return o;
}
} );
Object Links
Create()ing Links
var foo = {
something: function() {
console.log( "Tell me something good..." );
}
};
var bar = Object.create( foo );
bar.something(); // Tell me something good...
Object.create (..)๋ ์ง์ ํ ๊ฐ์ฒด foo์ ์ฐ๊ฒฐ๋ ์ ๊ฐ์ฒด bar๋ฅผ ์์ฑํ์ฌ Prototype ๋ฉ์ปค๋์ฆ์ ๋ชจ๋ ๊ถํ (์์)์ ์ ๊ณตํ๋ค.
Object.create() Polyfilled
Object.create()๋ ES5์ ์ถ๊ฐ๋์๋ค.
if (!Object.create) {
Object.create = function(o) {
function F(){}
F.prototype = o;
return new F();
};
}
var anotherObject = {
a: 2
};
var myObject = Object.create( anotherObject, {
b: {
enumerable: false,
writable: true,
configurable: false,
value: 3
},
c: {
enumerable: true,
writable: false,
configurable: false,
value: 4
}
} );
myObject.hasOwnProperty( "a" ); // false
myObject.hasOwnProperty( "b" ); // true
myObject.hasOwnProperty( "c" ); // true
myObject.a; // 2
myObject.b; // 3
myObject.c; // 4
Links As Fallbacks?
var anotherObject = {
cool: function() {
console.log( "cool!" );
}
};
var myObject = Object.create( anotherObject );
myObject.cool(); // "cool!"
๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ๋ฉด ํผ๋์ ๊ฐ์ค์ํฌ ์ ์๋ค.
ES6์์๋ "๋ฉ์๋๋ฅผ ์ฐพ์ ์ ์์" ์ ํ์ ๋์์ ์ ๊ณตํ ์์๋ ํ๋ก์๋ผ๋ ๊ณ ๊ธ ๊ธฐ๋ฅ์ด ๋์ ๋์๋ค. (๋ค์์ ๋ค๋ฃฐ๊ฒ)
๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ์.
var anotherObject = {
cool: function() {
console.log( "cool!" );
}
};
var myObject = Object.create( anotherObject );
myObject.doCool = function() {
this.cool(); // internal delegation!
};
myObject.doCool(); // "cool!"
Review (TL;DR)
์๋ฐ์คํฌ๋ฆฝํธ์์ ์์ ๋ฐ OOP ์ฉ์ด๋ค์ ๋ฌด์๋ฏธํ๋ค. ๊ด๊ณ๋ค์ด ๋ณต์ฌ๋ณธ์ด์๋๋ผ ์์๋งํฌ์ด๊ธฐ ๋๋ฌธ์ ์์์ด๋ผ๊ณ ๋ถ๋ฅด๋๊ฒ ์ ์ ํ๋ค.