[자바스크립트] 프로토타입 상속
글 작성자: 망고좋아
반응형
프로토타입 상속
- "
user
의 메서드를 복사하거나 다시 구현하지 않고user
에 약간의 기능을 얹어admin
과guest
객체를 만들 수 있지 않을까"를 프로토타입 상속을 이용해서 구현할 수 있다.
[[Prototype]]
- 자바스크립트의 객체는
[[Prototype]]
이라는 숨김 프로퍼티를 갖는다. - 이 숨김 프로퍼티 값은
null
이거나 다른 객체에 대한 참조가 되는데, 다른 객체를 참조하는 경우 참조 대상을 '프로토타입(prototype)'이라 부른다.
object
에서 프로퍼티를 읽으려고 하는데 해당 프로퍼티가 없으면 자바스크립트는 자동으로 프로토타입에서 프로퍼티를 찾는다. 이러한 동작 방식을 '프로토타입 상속'이라고 부른다.
// [[Prototype]] 프로퍼티는 내부 프로퍼티이면서 숨김 프로퍼티이지만 다양한 방법을 사용해 개발자가 값을 설정할 수 있다.
let animal = {
eats: true
};
let rabbit = {
jumps: true
};
rabbit.__proto__ = animal;
🔔 __proto__는 [[Prototype]]용 getter·setter이다.
__proto__
는[[Prototype]]
과 다르다.__proto__
는[[Prototype]]
의 getter(획득자)이자 setter(설정자)이다.- 최근 작성된 스크립트에선
__proto__
대신 함수Object.getPrototypeOf
나Object.setPrototypeOf
을 써서 프로토타입을 획득(get)하거나 설정(set)한다.
// 객체 rabbit에서 프로퍼티를 얻고싶은데 해당 프로퍼티가 없다면, 자바스크립트는 자동으로 animal이라는 객체에서 프로퍼티를 얻는다.
let animal = {
eats: true
};
let rabbit = {
jumps: true
};
rabbit.__proto__ = animal; // animal이 rabbit의 프로토타입이 되도록 설정
// 프로퍼티 eats과 jumps를 rabbit에서도 사용할 수 있게 되었다.
alert( rabbit.eats ); // true, rabbit.eats 프로퍼티를 읽으려 했는데, rabbit엔 eats라는 프로퍼티가 없다. 이때 자바스크립트는 [[Prototype]]이 참조하고 있는 객체인 animal에서 eats를 얻어낸다.
alert( rabbit.jumps ); // true
- 위 그림에서 “
rabbit
의 프로토타입은animal
입니다.” 혹은 "rabbit
은animal
을 상속받는다."라고 말할 수 있다. - 프로토타입을 설정해줘서
rabbit
에서도animal
에 구현된 유용한 프로퍼티와 메서드를 사용할 수 있다. - 이렇게 프로토타입에서 상속받은 프로퍼티를 '상속 프로퍼티(inherited property)'라고 한다.
상속 프로퍼티를 사용해 animal
에 정의된 메서드를 rabbit
에서 호출
let animal = {
eats: true,
walk() {
alert("동물이 걷습니다.");
}
};
let rabbit = {
jumps: true,
__proto__: animal
};
// 메서드 walk는 rabbit의 프로토타입인 animal에서 상속받았다.
rabbit.walk(); // 동물이 걷습니다.
프로토타입 체이닝
let animal = {
eats: true,
walk() {
alert("동물이 걷습니다.");
}
};
let rabbit = {
jumps: true,
__proto__: animal
};
let longEar = {
earLength: 10,
__proto__: rabbit
};
// 메서드 walk는 프로토타입 체인을 통해 상속받았다.
longEar.walk(); // 동물이 걷습니다.
alert(longEar.jumps); // true (rabbit에서 상속받음)
프로토타입 체이닝 제약 사항 2가지
- 순환 참조(circular reference)는 허용되지 않는다.
__proto__
를 이용해 닫힌 형태로 다른 객체를 참조하면 에러가 발생한다. __proto__
의 값은 객체나null
만 가능하다. 다른 자료형은 무시된다.
⚠️ 프로토타입은 프로퍼티를 읽을 때만 사용한다.
- 프로퍼티를 추가, 수정하거나 지우는 연산은 객체에서 직접 해야 한다.
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 함수가 실행된다!
admin.fullName = "Alice Cooper"; // (**)
alert(admin.fullName); // Alice Cooper , state of admin modified
alert(user.fullName); // John Smith , state of user protected
this는 프로토타입에 영향을 받지 않는다.
- 메서드를 객체에서 호출했든 프로토타입에서 호출했든 상관없이
this
는 언제나.
앞에 있는 객체가 된다. - 위 코드에서는
admin.fullName=
으로 setter 함수를 호출할 때,this
는user
가 아닌admin
이 된다.
// animal엔 다양한 메서드가 있다.
let animal = {
walk() {
if (!this.isSleeping) {
alert(`동물이 걸어갑니다.`);
}
},
sleep() {
this.isSleeping = true;
}
};
let rabbit = {
name: "하얀 토끼",
__proto__: animal
};
// rabbit의 프로퍼티 isSleeping을 true로 변경한다.
rabbit.sleep();
alert(rabbit.isSleeping); // true
alert(animal.isSleeping); // undefined (프로토타입에는 isSleeping이라는 프로퍼티가 없다.)
- 상속받은 메서드의
this
는animal
이 아닌 실제 메서드가 호출되는 시점의 점(.
) 앞에 있는 객체가 된다. - 따라서
this
에 데이터를 쓰면animal
이 아닌 해당 객체의 상태가 변화한다. - 결론 : 메서드는 공유되지만, 객체의 상태는 공유되지 않는다.
Object.prototype.hasOwnProperty()
hasOwnProperty()
메소드는 객체가 특정 프로퍼티를 가지고 있는지를 나타내는 불리언 값을 반환한다.
const object1 = {};
object1.property1 = 42;
console.log(object1.hasOwnProperty('property1')); //true
console.log(object1.hasOwnProperty('toString')); // false
console.log(object1.hasOwnProperty('hasOwnProperty')); // false
for…in 반복문
for..in
은 상속 프로퍼티도 순회대상에 포함시킨다.
let animal = {
eats: true
};
let rabbit = {
jumps: true,
__proto__: animal
};
javascript
// Object.keys는 객체 자신의 키만 반환한다.
alert(Object.keys(rabbit)); // jumps
// for..in은 객체 자신의 키와 상속 프로퍼티의 키 모두를 순회한다.
for(let prop in rabbit) alert(prop); // jumps, eats
// obj.hasOwnProperty(key)를 응용하면 아래 예시에서처럼 상속 프로퍼티를 걸러낼 수 있고, 상속 프로퍼티만을 대상으로 무언가를 할 수도 있다.
let animal = {
eats: true
};
let rabbit = {
jumps: true,
__proto__: animal
};
for(let prop in rabbit) {
let isOwn = rabbit.hasOwnProperty(prop);
if (isOwn) {
alert(`객체 자신의 프로퍼티: ${prop}`); // 객체 자신의 프로퍼티: jumps
} else {
alert(`상속 프로퍼티: ${prop}`); // 상속 프로퍼티: eats
}
}
for..in
은 오직 열거 가능한 프로퍼티만 순회 대상에 포함하기 때문에hasOwnProperty
는 얼럿창에 출력되지 않습니다. (hasOwnProperty는 열거 가능한(enumerable) 프로퍼티가 아니기 때문에)
📌 참고
반응형
'프로그래밍 > JavaScript' 카테고리의 다른 글
[자바스크립트] Location 객체 (0) | 2021.08.11 |
---|---|
[자바스크립트] 함수의 prototype 프로퍼티 (0) | 2021.07.16 |
[자바스크립트] getter와 setter (0) | 2021.07.15 |
[자바스크립트] 다시 보는 화살표 함수 (0) | 2021.07.15 |
[자바스크립트] JSON.stringify(value), JSON.parse() (0) | 2021.07.13 |
댓글
이 글 공유하기
다른 글
-
[자바스크립트] Location 객체
[자바스크립트] Location 객체
2021.08.11 -
[자바스크립트] 함수의 prototype 프로퍼티
[자바스크립트] 함수의 prototype 프로퍼티
2021.07.16 -
[자바스크립트] getter와 setter
[자바스크립트] getter와 setter
2021.07.15 -
[자바스크립트] 다시 보는 화살표 함수
[자바스크립트] 다시 보는 화살표 함수
2021.07.15