prototype inheritance - Lee-hyuna/33-js-concepts-kr GitHub Wiki
μν μμ
μλ¬Έ: Prototypal inheritance
νλ‘κ·Έλλ°μμ μ’ μ’ λ¬΄μΈκ°λ₯Ό νμ₯νκΈ°λ₯Ό μνλ€.
μλ₯Όλ€μ΄, μμ±λ€κ³Ό λ©μλλ₯Ό κ°μ§ user κ°μ²΄κ° μκ³ μ΄λ₯Ό μ½κ° λ³ννμ¬ adminκ³Ό guestλ₯Ό λ§λλ €κ³ ν λ userμ μλ κ²λ€μ μ¬μ¬μ©νκ³ μΆμ κ²μ΄λ€. μ¦, λ©μλλ₯Ό 볡μ¬/μ¬μμ±νμ§ μκ³ μλ‘μ΄ κ°μ²΄λ₯Ό λ§λ€κ³ μΆμ κ²μ΄λ€.
μ΄λ₯Ό μν΄ μν μμ(Prototypal inheritance)μ΄λΌλ νΉμ§μ΄ μ‘΄μ¬νλ€.
Prototype
μλ°μ€ν¬λ¦½νΈμ κ°μ²΄(object)λ null μ΄κ±°λ λ€λ₯Έ κ°μ²΄λ₯Ό μ°Έμ‘°νλ μ¨κ²¨μ§ μμ±μΈ [Prototype](/Lee-hyuna/33-js-concepts-kr/wiki/Prototype)μ κ°μ§κ³ μλ€. (μ€ν λ¬Έμμ μ νμλ―μ΄). μ΄ κ°μ²΄λ₯Ό "νλ‘ν νμ
"μ΄λΌ νλ€.
νλ‘ν νμ
μ μ½κ° λ§λ²κ°λ€. objectμμ μμ± κ°μ μ κ·Όνλ €κ³ ν λ, ν΄λΉ κ°μ΄ μ‘΄μ¬νμ§ μμΌλ©΄ μλ°μ€ν¬λ¦½νΈλ μλμ μΌλ‘ κ·Έ κ°μ²΄μ νλ‘ν νμ
(μν)μμ κ·Έ κ°μ κ°μ Έμ¨λ€. λ§μ μΈμ΄λ€μ νΉμ§λ€κ³Ό νλ‘κ·Έλλ° κΈ°μ μ΄ μ΄λ₯Ό ν λλ‘νλ€.
[Prototype](/Lee-hyuna/33-js-concepts-kr/wiki/Prototype) μμ±μ λ΄λΆμ μΌλ‘ μ¨κ²¨μ Έ μλλ°, μ΄λ₯Ό μ€μ νλ λ°©λ²μ μ¬λ¬κ°μ§κ° μ‘΄μ¬νλ€.
κ·Έ μ€ νλκ° μλμ κ°μ΄ __proto__λ₯Ό μ¬μ©νλ κ²μ΄λ€.
let animal = {
eats: true
};
let rabbit = {
jumps: true
};
rabbit.__proto__ = animal;
__proto__λ[Prototype](/Lee-hyuna/33-js-concepts-kr/wiki/Prototype)μ μν historical getter/setterμ΄λ€.
__proto__μ[Prototype](/Lee-hyuna/33-js-concepts-kr/wiki/Prototype)κ³Ό _κ°μ§ μλ€_λ κ²μ κΈ°μ΅ν΄λΌ.__proto__λ[Prototype](/Lee-hyuna/33-js-concepts-kr/wiki/Prototype)μ getter/setterμ΄λ€.
__proto__λ μμ¬μ μ΄μ λ‘ μ‘΄μ¬νλλ°, νλ μΈμ΄μμλObject.getPrototypeOf/Object.setPrototypeOfκ°μ ν¨μ ννλ‘ λ체λμλ€. μ’ λ λμ€μ λ체λ μ΄μ μ ν΄λΉ ν¨μλ₯Ό μ΄ν΄ λ³Ό κ²μ΄λ€.μ€νμ λ°λ₯΄λ©΄
__proto__λ λΈλΌμ°μ μ μν΄μλ§ μ§μλμ΄μΌ νμ§λ§, μ¬μ€ μλ² μΈ‘μ λΉλ‘―ν λͺ¨λ νκ²½μμ μ§μνλ€. μ§κΈλΆν΄__proto__νκΈ°λ²μ΄ μ‘°κΈ λ μ§κ΄μ μΌλ‘ λͺ λ°±νλ―λ‘ μμ μμ μ¬μ©ν κ²μ΄λ€.
rabbitμ μ΄λ€ μμ±μ μ°Ύλλ° κ·Έκ²μ΄ μλ€λ©΄, μλ°μ€ν¬λ¦½νΈλ μλμ μΌλ‘ animalμμ μ°Ύμ κ²μ΄λ€.
μλ₯Ό λ€μ΄:
let animal = {
eats: true
};
let rabbit = {
jumps: true
};
rabbit.__proto__ = animal; // (*)
// we can find both properties in rabbit now:
alert( rabbit.eats ); // true (**)
alert( rabbit.jumps ); // true
μ¬κΈ°(*)κ° νμλ μ€μμ rabbitμ νλ‘ν νμ
(μν)μ animalμ€μ νκ³ μλ€.
μ΄ν, alertμ΄ (**)μμ rabbit.eatsμμ±μ μ½μΌλ € ν λ, rabbitμλ ν΄λΉ μμ±μ΄ μ‘΄μ¬νμ§ μλλ€. λ°λΌμ μλ°μ€ν¬λ¦½νΈλ [Prototype](/Lee-hyuna/33-js-concepts-kr/wiki/Prototype) μ°Έμ‘°λ₯Ό λ°λΌκ° animalμμ ν΄λΉ μμ±μ μ°ΎμλΈλ€. (μ΄λ μλμλΆν° μ°Ύλλ€).
μ΄κ²μ "animalμ rabbitμ νλ‘ν νμ
"λΌκ³ νκ±°λ "rabbitμ animalμΌλ‘ λΆν° νν λ‘νμ
μμμ λ°λλ€."λΌκ³ ν μ μλ€.
κ·Έλμ animalμ΄ λ§μ μ μ©ν μμ±λ€κ³Ό λ©μλλ₯Ό κ°μ§κ³ μλ€λ©΄, rabbitμμ μλμΌλ‘ μ¬μ©ν μ μκ² λλ€. κ·Έλ¬ν μμ±λ€μ "inherited" λΌκ³ λΆλ₯Έλ€.
animalμ νΉμ λ©μλκ° μ‘΄μ¬νλ©΄, rabbitμμλ νΈμΆν μ μλ€.:
let animal = {
eats: true,
walk() {
alert("Animal walk");
}
};
let rabbit = {
jumps: true,
__proto__: animal
};
// walk is taken from the prototype
rabbit.walk(); // Animal walk
μλμ κ°μ΄, ν΄λΉ λ©μλ(walk)λ μλμ μΌλ‘ νλ‘ν νμ
μμ κ°μ Έμμ§λ€.
μ΄λ¬ν νμμ νλ‘ν νμ 체μΈμ΄λΌ νλλ°, νλ‘ν νμ 체μΈμ λ κΈΈμ΄μ§ μ μλ€.
let animal = {
eats: true,
walk() {
alert("Animal walk");
}
};
let rabbit = {
jumps: true,
__proto__: animal
};
let longEar = {
earLength: 10,
__proto__: rabbit
};
// walk is taken from the prototype chain
longEar.walk(); // Animal walk
alert(longEar.jumps); // true (from rabbit)
λ¨, λκ°μ§μ μ μ½μ¬νμ΄ μλ€.
- μ°Έμ‘°λ μνμ΄ λμ΄μ μλλ€.
__proto__λ₯Ό μννλλ‘ ν λΉνλ©΄ μλ°μ€ν¬λ¦½νΈλ μ€λ₯λ₯Ό λμ§ κ²μ΄λ€. __proto__μ κ°μ κ°μ²΄μ΄κ±°λnullμ΄μ΄μΌνλ€. μμ κ°κ³Ό κ°μ λ€λ₯Έ νμ λ€μ 무μλλ€.
λν λΉμ°νκ²λ [Prototype](/Lee-hyuna/33-js-concepts-kr/wiki/Prototype)μ μ€μ§ νκ°λ§ κ°μ§ μ μλ€. ν κ°μ²΄λ λκ°μ κ°μ²΄μμ λμμ μμ λ°μ μ μλ€.
κ°μ μ°λ κ²μ νλ‘ν νμ μ μ¬μ©νμ§ μκΈ°
νλ‘ν νμ μ μ½κΈ° μ μ© μμ±μ΄λ€.
κ·Έλ¬λ μμ±μ μ°κ³ /μ½λ μ°μ°μ κ°μ²΄μ μ§μ μ μΌλ‘ μ μ©ν μ μλ€.
μλμ μλ₯Ό 보면, walk λ©μλλ₯Ό rabbitμ ν λΉνκ³ μλ€.
let animal = {
eats: true,
walk() {
/* this method won't be used by rabbit */
}
};
let rabbit = {
__proto__: animal
};
rabbit.walk = function() {
alert("Rabbit! Bounce-bounce!");
};
rabbit.walk(); // Rabbit! Bounce-bounce!
μ΄μ , rabbit.walk()μ νΈμΆμ νλ‘ν νμ
μ μ¬μ©νμ§ μκ³ κ°μ²΄μμ μ¦μ μ°Ύμμ Έ μ€νλ κ²μ΄λ€.
μ΄λ λ°μ΄ν° μμ±λ§μ μν κ²μ΄μ§ μ κ·Όμλ₯Ό μν κ²μ μλλ€. μμ±μ΄ getter/setter λΌλ©΄ ν¨μμ²λΌ λμνλ€. getter/setterλ νλ‘ν νμ μ λ°λΌλ³Έλ€.
κ·Έλ° μ΄μ λ‘, admin.fullNameμ μλ μ½λμ κ°μ΄ μ μμ μΌλ‘ λμνλ€.
let user = {
name: "John",
surname: "Smith",
set fullName(value) {
[this.name, this.surname] = value.split(" ");
},
get fullName() {
return `${this.name} ${this.surname}`;
}
};
let admin = {
__proto__: user,
isAdmin: true
};
alert(admin.fullName); // John Smith (*)
// setter triggers!
admin.fullName = "Alice Cooper"; // (**)
(*)λΌμΈμ admin.fullNameμμ±μ user νλ‘ν νμ
μμ getterλ₯Ό κ°μ§κ³ μλ€, κ·Έλμ νΈμΆλ κ²μ΄λ€. κ·Έλ¦¬κ³ (**)λΌμΈμ μμ±μ νλ‘ν νμ
μμ setterλ₯Ό κ°μ§κ³ μλ€. λλ¬Έμ νΈμΆλ κ²μ΄λ€.
"this" κ°
μμ μμ μμ ν₯λ―Έλ‘μ΄ μ§λ¬Έμ΄ λμ¬ μ μλ€: set fullName(valuie)μμ thisλ μ΄λ€ κ°μ κ°μ§κ³ μμκΉ? μ½λ μ μ΄λ μμΉμμ this.nameκ³Ό this.surnameμ μ°μ¬μ‘μκΉ? user λλ admin? λ΅μ κ°λ¨νλ€.
thisλ νλ‘ν νμ
μ μν΄ μ ν μν₯μ λ°μ§ μλλ€.
λ©μλκ° μ΄λμ λ°κ²¬ λλκ°μ, λ©μλ νΈμΆμμ thisλ μΈμ λ . μ°μ° μμ μλ κ°μ²΄λ₯Ό κ°λ₯΄ν¨λ€.
κ·Έλμ, setterκ° admin.fullName=λ₯Ό νΈμΆν λ userκ° μλ adminμ thisλ‘ μ¬μ©νλ€.
μ΄κ±΄ μ¬μ€ λ§€μ° λ§€μ° μ€μν μ¬μ€μ΄λ€. μλνλ©΄ λ§μ λ©μλλ₯Ό κ°μ§ κ°μ²΄λ₯Ό κ°μ§κ³ μκ³ μ΄ κ°μ²΄λ₯Ό μμλ°μ κ°μ²΄κ° μ‘΄μ¬νλ€κ³ μκ°ν΄λ³΄μ. κ·Έ νμ λΆλͺ¨ κ°μ²΄μ λ©μλλ₯Ό μμλ κ°μ²΄μμ μ€ννλ€λ©΄, λΆλͺ¨ κ°μ²΄μ μνκ°μ΄ μλ μμ κ°μ²΄μ μν κ°μ μμ ν κ²μ΄λ€,
μλ₯Ό λ€μ΄, animalκ° "λ©μλ μ μ₯μ"λΌκ³ κ°μ νκ³ , rabbitμ μ΄κ²μ μ¬μ©νλ€ μΉμ.
rabbit.sleep()νΈμΆμ this.isSleepingμ rabbitκ°μ²΄μ ν λΉν κ²μ΄λ€.
// animal has methods
let animal = {
walk() {
if (!this.isSleeping) {
alert(`I walk`);
}
},
sleep() {
this.isSleeping = true;
}
};
let rabbit = {
name: "White Rabbit",
__proto__: animal
};
// modifies rabbit.isSleeping
rabbit.sleep();
alert(rabbit.isSleeping); // true
alert(animal.isSleeping); // undefined (no such property in the prototype)
κ²°κ³Όλ κ·Έλ¦Όκ³Ό κ°λ€.
animalλ‘ λΆν° μμν birdλ snake λ±μ κ°μ²΄λ₯Ό κ°μ§κ³ μλ€κ³ κ°μ ν΄λ³΄μ. μ΄ κ²λ€λ μμ animalμ λ©μλλ€μ μ κ·Όν μ μμ κ²μ΄λ€. νμ§λ§ κ° λ©μλμ thisλ animalμ΄ μλλΌ . μ΄μ μ νΈμΆ μμ μ νκ°λ κ° κ°μ²΄μ λμν κ²μ΄λ€. κ·Έλμ thisμ λ°μ΄ν°λ₯Ό μ μ₯ν λ, μ΄ κ°μ²΄λ€μ μ μ₯νλ κ²μ΄λ€.
κ²°κ³Όμ μΌλ‘ λ©μλλ 곡μ λμ§λ§, κ°μ²΄μ μν κ°μ 곡μ λμ§ μλλ€.
forβ¦in loop
for..inμ μμλ°μ μμ±λ€λ μννλ€.
μλ₯Ό λ€μ΄:
let animal = {
eats: true
};
let rabbit = {
jumps: true,
__proto__: animal
};
// Object.keys only return own keys
alert(Object.keys(rabbit)); // jumps
// for..in loops over both own and inherited keys
for(let prop in rabbit) alert(prop); // jumps, then eats
μνλ κ²°κ³Όκ° μ΄κ²μ΄ μλ κ²μ΄λ€. μμ λ°μ μμ±μ μ μΈνκ³ μΆμ κ²μ΄λ€. μ΄λ₯Ό μν λ΄μ₯ λ©μλ obj.hasOwnProperty(key)κ° μλ€. μ΄ λ©μλλ μμ± μ΄λ¦ keyκ° objκ° κ°μ§ μμ±μ΄λ©΄ (μμ λ°μ κ²μ΄ μλλΌ), trueλ₯Ό λ°ννλ€.
λ°λΌμ μμλ μμ±λ€μ κ±Έλ¬λΌ μ μλ€.
let animal = {
eats: true
};
let rabbit = {
jumps: true,
__proto__: animal
};
for(let prop in rabbit) {
let isOwn = rabbit.hasOwnProperty(prop);
if (isOwn) {
alert(`Our: ${prop}`); // Our: jumps
} else {
alert(`Inherited: ${prop}`); // Inherited: eats
}
}
λ€μκ³Ό κ°μ μμ 체μΈμ΄ μλ€. rabbitμ animalμ μμ λ°κ³ animalμ Obejct.prototypeμΌλ‘ λΆν° μμ λ°μ κ²μ΄λ€. μλνλ©΄ κΈ°λ³Έμ μΌλ‘, animalμ 리ν°λ΄ κ°μ²΄ {...} μ΄κΈ° λλ¬Έμ΄λ€. κ·Έλ¦¬κ³ Obejct.prototypeμ nullμ λ°λΌλ³Έλ€.
μ¬κΈ°μμ μ¬λ―Έμλ μ μ΄ μλ€. rabbit.hasOwnPropertyλ μ΄λμ λμ¨ κ²μΌκΉ? μ°λ¦¬λ ν΄λΉ λ©μλλ₯Ό μ μνμ§ μμλ€. μμ 체μΈμ 보면, Object.prototype.hasOwnPropertyμ μν΄ μ 곡λ λ©μλμμ μ μ μλ€. μ¦, μ΄κ±΄ μμ λ°μ κ²μ΄λ€.
κ·Έλ¬λ μμλ μμ±λ€λ λμ΄νλ for..in λ°λ³΅μμ, μ eats μ΄λ jumpsμ²λΌ hasOwnPropertyκ° λ³΄μ΄μ§ μμκΉ?
λ΅μ κ°λ¨νλ€. hasOwnPropertyλ μ΄κ±°κ°λ₯(enumerable)ν μμ±μ΄ μλκΈ° λλ¬Έμ΄λ€. μ΄μ κ°μ΄ Object.prototypeμμ±λ€μ enumerable:false κ°μ κ°μ§κ³ μλ€. μ΄κ² λ°λ‘ λ°λ³΅μμ 보μ΄μ§ μλ μ΄μ μ΄λ€.
λͺ¨λ λ€λ₯Έ λ°λ³΅ λ©μλλ€μ μμ μμ±μ 무μνλ€
Object.keys,Object.valuesμ κ°μ key / valueλ₯Ό κ°μ Έμ€λ λ©μλλ€μ μμλ κ°μ 무μνλ€.μ΄λ€μ μ€μ§ κ°μ²΄ μμ²΄κ° κ°μ§ κ°μ κ°μ Έμ¨λ€,
μμ½
- μλ°μ€ν¬λ¦½νΈμμ, λͺ¨λ κ°μ²΄λ μ¨κ²¨μ§
[Prototype](/Lee-hyuna/33-js-concepts-kr/wiki/Prototype)μμ±μ κ°λλ€. κ·Έλ¦¬κ³ μ΄ μμ±μ λλ€λ₯Έ κ°μ²΄μ΄κ±°λnullμ΄λ€. obj.__proto__λ₯Ό μ¬μ©νμ¬ μ΄ μμ±μ μ κ·Όν μ μλ€.[Prototype](/Lee-hyuna/33-js-concepts-kr/wiki/Prototype)μ μν΄ μ°Έμ‘°λλ κ°μ²΄λ₯Ό "νλ‘ν νμ (μν)"μ΄λΌκ³ νλ€.objμ μμ±μ μ½κ±°λ λ©μλλ₯Ό νΈμΆνκ³ μΆμλ° μ‘΄μ¬νμ§ μλλ€λ©΄, μλ°μ€ν¬λ¦½νΈλ νλ‘ν νμ μμ κ·Έκ²μ μ°ΎμΌλ € ν κ²μ΄λ€.- μ½κΈ°/μ§μ°κΈ° μ°μ°μ κ°μ²΄μ μ§μ μ μΌλ‘ μ μ©λλ€. νλ‘ν νμ μ μ¬μ©νμ§ μλλ€.(setterκ° μλ λ°μ΄ν° μμ±μ΄λΌ κ°μ νμ κ²½μ°).
obj.method()λ₯Ό νΈμΆνκ³ , ν΄λΉmethodκ° νλ‘ν νμ μμ κ°μ Έμ¨ κ²μ΄λΌλ©΄,thisλ μ¬μ νobjλ₯Ό ν¨λ€. μ¬μ§μ΄ λ©μλλ€μ΄ μμλ¬λ€ νλλΌλ λ©μλλ€μ μΈμ λ νμ¬ κ°μ²΄μ μ μ©λ κ²μ λλ€.for..in루νλ μμ μ κ°κ³Ό μμλ κ°μ λ°λ³΅νλ€. κ·Έ μΈμ key/valueλ₯Ό κ°μ Έμ€λ λ€λ₯Έ λͺ¨λ λ©μλλ€μ μ€μ§ κ·Έ μμ μ κ°μ²΄μ μμ±λ§ κ°μ Έμ¨λ€.