script 기초 - 프로토타입
프로토타입 상속
사람에 관한 프로퍼티와 메서드를 가진 user
라는 객체가 있다고 해보자. 이 때 user
와 상당히 유사하지만 약간의 차이가 있는 admin
과 guest
라는 객체를 만들어야 한다고 가정해보자. 프로토타입 상속(prototypal inheritance)을 이용하면, user에 약간의 기능을 얹어 admin
과 guest
객체를 만들 수 있다.
✔️ [[Prototype]]
객체는 [[Prototype]]
이라는 숨김 프로퍼티를 갖는다. 이 숨김 프로퍼티 값은 null
이거나 다른 객체에 대한 참조가 되는데, 다른 객체를 참조하는 경우 참조 대상이 '프로토타입'이 된다.
👉🏻 object
에서 프로퍼티를 읽으려고 하는데 해당 프로퍼티가 없으면, 자바스크립트는 자동으로 프로토타입에서 프로퍼티를 찾는다. 이러한 동작 방식을 '프로토타입 상속' 이라고 한다.
🔍 __proto__
__proto__
는 [[Prototype]]용 getter(획득자)이자 setter(설정자)이다.
비교적 근래에 작성된 스크립트에선 __proto__
대신 함수 Object.getPrototypeOf
나 Object.setPrototypeOf
을 써서 프로토타입을 획득(get)하거나 설정(set)한다.
✔️ 프로토타입 체이닝
다른 객체를 참조하는 것이 이어지면 프로토타입 체이닝이 발생한다. 프로토타입 체이닝에는 두 가지 제약사항이 있다.
- 순환 참조는 허용되지 않는다.
__proto__
를 이용해 닫힌 형태로 다른 객체를 참조하면 에러가 발생한다. __proto__
의 값은 객체나 null만 가능하다. 다른 자료형은 무시된다.- 당연히 하나의 객체는 오직 하나의
[[Prototype]]
만 있을 수 있다.
✔️ 프로토타입은 프로퍼티를 읽을 때만 사용한다.
만약 walk
라는 메서드를 가진 animal
이라는 객체가 있고 이를 참조하는 객체 rabbit
이 있다고 치자. 이 때 rabbit
에 walk
라는 메서드를 새로 호출하면, 프로토타입에 있는 메서드가 실행되는 것이 아니라 rabbit
에 추가한 walk
가 실행된다.
그러나 접근자 프로퍼티는 setter 함수로 프로퍼티에 값을 할당하므로 이 규칙이 적용되지 않는다. 접근자 프로퍼티에 값을 할당하는 것은 함수를 호출하는 것과 같으므로, 문제 없이 실행될 것이다.
요약 : 접근자 프로퍼티가 아닌 데이터프로퍼티를 다루고 있다면, 쓰기나 지우기와 관련된 연산은 프로토타입을 통하지 않고 객체에 직접 적용된다.
✔️ 'this'는 언제나 .앞의 객체가 된다.
메서드를 객체에서 호출했든, 프로토타입에서 호출했든 상관없이 this는 언제나 .앞에 있는 객체가 된다.
상속받은 메서드를 사용하더라도 객체는 프로토타입이 아닌 자신의 상태를 수정한다.
메서드는 공유되지만, 객체의 상태는 공유되지 않는다.
✔️ for...in 반복문
let animal = {
eats : true
};
let rabbit = {
jumps : true,
__proto__ : animal
};
//Object.keys는 객체 자신의 키만 반환
alert(Object.keys(rabbit); //jumps
// for...in은 객체 자신의 키와 상속 프로퍼티의 키 모두를 순회
for(let prop in rabbit) alert(prop); //jumps, eats
함수의 prototype 프로퍼티
new F()와 같은 생성자 함수를 이용하면 새로운 객체를 만들 수 있다.
이 때 F.prototype
이 객체면 new
연산자는 F.prototype
을 사용해 새롭게 생성된 객체의 [[Prototype]]
을 설정한다.
🙋🏻♀️ F.prototype
에서 "prototype"은 '프로토타입' 객체가 아니라 F
에 정의된 일반 프로퍼티이다.
이거 좀.. 신기하네
let animal = {
eats : true
}
function Rabbit(name) {
this.name = name;
}
Rabbit.prototype = animal;
let rabbit = new Rabbit("White Rabbit"); // rabbit.__proto__ == animal
alert( rabbit.eats ); //true
Rabbit.prototype = animal
은 new Rabbit
을 호출해 만든 새로운 객체(rabbit)의 [[prototype]]
을 animal
로 설정하라는 뜻 ~
✔️ 함수의 prototype 프로퍼티와 consturctor 프로퍼티
개발자가 특별히 할당하지 않더라도 모든 함수는 "prototype"
프로퍼티를 갖는다.
function Rabbit (){}
//Rabbit.prototype = { constructor : Rabbit };
프로토타입 메서드와 proto가 없는 객체
__proto__
는 다소 구식이기 때문에 더는 사용하지 않는 것이 좋다.
대신 사용할 수 있는 모던한 메서드가 있다는 점!
Object.create(proto, [descriptors])
:[[prototype]]
이proto
를 참조하는 빈 객체를 만든다. 이 때 프로퍼티 설명자를 추가로 넘길 수 있다.Object.getPrototype(obj)
:obj
의[[prototype]]
을 반환Object.setPrototype(obj, proto)
:obj
의[[prototype]]
이proto
가 되도록 설정
🔍 프로퍼티 플래그와 설명자
객체 프로퍼티 추가 구성 옵션에 대해 알아보자.
프로퍼티 플래그
객체 프로퍼티는 값(value)과 함께 플래그(flag)라 불리는 특별한 속성 세 가지를 갖는다.
-
writable
:true
이면 값 수정 가능,false
면 읽기만 가능 -
enumerable
:true
이면 반복문을 사용해 나열 가능. -
configurable
:true
이면 프로퍼티 삭제나 플래그 수정 가능 -
Object.getOwnPropertyDescriptor(obj, propertyName)
: 특정 프로퍼티에 대한 정보를 모두 얻을 수 있다. -
Object.defineProperty(obj, propertyName, descriptor)
:obj
,propertyName
은 설명자를 적용하고 싶은 객체와 프로퍼티,descriptor
는 적용하고자 하는 프로퍼티 설명자.
-> 이 메서드는 객체에 해당 프로퍼티가 있으면 플래그를 원하는대로 변경해준다. 프로퍼티가 없으면 인수로 넘겨받은 정보를 이용해 새로운 프로퍼티를 만든다. 이때 플래그 정보가 없으면 플래그값은 자동으로false
가 된다. -
Object.defineProperties
: 프로퍼티 여러개를 한 번에 정의할 수 있다.
Object.defineProperties(user, {
name : { value : "john" , writable : false },
surname : {value : "smith", writable : false },
// ...
});
Object.getOwnPropertyDescriptor
: 프로퍼티 설명자를 전부 한꺼번에 가져올 수 있다.Object.defineProperties
와 함께 사용하면 객체 복사시 플래그도 함께 복사할 수 있다. 심볼형 프로퍼티를 포함한 프로퍼티 설명자 전체를 반환.
let clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj));
Author And Source
이 문제에 관하여(script 기초 - 프로토타입), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@gadongkim/Javascript07저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)