프로토타입을 쓰는 이유
Person의 생성자 함수는 한가지 문제가 있다.
Person 생성자 함수를 이용하여 여러 객체를 만들었을 경우
name은 각자 고유한 이름을 가지지만,
setName이란 함수는 모두 같은 내용을 보유하게 될거면서
각각 1명씩 setName을 가지게 된다.
이에 상속/재사용을 구현하기 위해 프로토타입이란 걸 사용한다.
프로토타입 간단개념
constructor 함수는 prototype 객체를 보유하고 있음
(constructor 함수가 뭔지 모른다면 아래 링크)
https://yamyam-naengmyeon-donkats.tistory.com/121
Person 함수로 인해 생성된 객체들은
객체들이 모두 가지고 있는 [[prototype]] 내부슬롯을 통하여
Person 생성자 함수가 보유한 prototype 객체를 가리킴
내부슬롯은 보통 참조를 할 수 없지만
[[prototype]] 내부슬롯은 "__proto__" 라는 접근자 프로퍼티로 참조를 할 수 있음
실제 브라우저 콘솔로 확인
이 같은 개념으로 상속/재사용 을 구현할 수 있음
프로토타입 사용해보기
첫번째 단락 "프로토타입을 쓰는 이유" 에서 나왔던 문제를 해결해봄
이제 person 객체들은 각자가 setName을 굳이 보유하지 않아도,
부모인 Person의 prototype 객체를 __proto__ 접근자 프로퍼티로 참조하여
낭비없이 사용할 수 있다.
프로토타입 객체의 constructor
contructor 프로퍼티는 prototype 객체의 프로퍼티로 자신을 참조하고 있는 생성자 함수를 가리킴
리터럴로 생성된 객체는 참조하는 프로토타입이 없는가
아님.
일단 리터럴로 생성하지 않고 Object 생성자 함수로 생성한 예시를 소개
빌트인 객체인 Object 생성자 함수를 이용해도 마찬가지로
constructor는 부모를 잘 가리킴
리터럴로 생성하면 어떻게 될까
똑같은 결과를 보여줌
이에 대해선 자바스크립트 엔진 내부에서 추상 연산 "OrdinaryObjectCreate를 호출하여
Object.prototype을 참조하는 객체를 생성한다 함
프로토타입 체인
js는 객체의 프로퍼티에 접근할 시,
프로퍼티를 찾지 못한다면
__proto__ 접근자 프로퍼티에서 찾으하는 습성이 있다.
이를 프로토타입 체인이라 함
일단 Object의 prototype에는 hasOwnProperty 라는 함수가 있음
1. 리터럴로 생성한 오브젝트
ㄱ. 리터럴로 생성한 오브젝트들은 모두 __proto__로 Object 생성자 함수의 prototype 객체를 가리킬것임
ㄴ. 리터럴로 생성한 오브젝트들이 바로 hasOwnProperty에 접근해도 탐색가능함
ㄷ. 프로토타입 체인의 습성때문에 hasOwnProperty 프로퍼티가 없다면 Object 생성자 함수의 prototype 객체에 접근을 할 것이고, 그 곳에서 탐색 성공할 것
귀찮아서 검증코드는 안짬
2. 내가 직접 만든 생성자 함수로 생성한 오브젝트 (원리는 같음)
ㄱ. 이 오브젝트의 __proto__ 접근자 프로퍼티는 바로 Object 생성자 함수의 prototype 객체를 가리키진 않을것
ㄴ. 내가 직접 만든 생성자 함수의 prototype 객체를 가리킬 것
ㄷ. 허나, 내가 직접 만든 생성자 함수에서도 hasOwnProperty 프로퍼티는 없기 때문에 프로토타입 체인이 두 번 발현되서 결국엔 Object 생성자 함수의 prototype에 접근함
오버라이딩
__proto__의 프로퍼티와 같은 이름의 프로퍼티를 추가하면,
오버라이딩 되는것이 아닌 새로운 프로퍼티로 추가된다.
같은 이름의 프로퍼티가 두 개 생기는 것은 아니고,
__proto__를 이용하여 추가한 객체(자식)의 __proto__에만 덮어씌워짐
이처럼 프로퍼티가 가려지는 현상을 "프로퍼티 섀도잉" 이라 함
p1.__proto__setName 은 변경이 되었지만
prototype 객체를 보유한 Person 생성자 함수에서 확인해보면 setName은 원래 그대로를 유지하고 있다.
즉 하위 객체에서 상위 프로토타입의 프로퍼티를 변경,삭제하는 것은 불가능함
프로토타입 교체하기
- 생성자 함수 내에서 프로토타입 교체하기
prototype이 정상적으로 변경되었지만,
잘 살펴보면 constructor 프로퍼티가 없음
constructor 프로퍼티는 자바스크립트 엔진이 프로토타입을 생성할때 자동으로 추가한 프로퍼티임.
만일 Person 생성자 함수로 한 객체를 생성하였고,
그 객체의 원산지를 알기위해 constructor 를 이용하였다면 오해가 생길 수 있음
위 상황을 방지하기 위해 프로토타입을 교체하였다면 constructor도 달아주어야 함
- 인스턴스로 프로토타입 교체하기
"오버라이딩" 단락에 있는 예시같음
__proto__를 이용하여 변경하는 것인데,
이는 prototype객체자체가 바귀는것이 아닌 __proto__ 접근자 프로퍼티의 값이 바뀌는 것이라
생성자 함수 내에서 프로토타입을 교체하는 것과는 차이가 있음
참고로 이 상황에서도 construct를 추가해주어야함
instanceof 연산자
instanceof 연산자로 A 객체가 B의 프로토타입 체인내에 존재하는지 확인할 수 있다.
ex) "객체" instance of "생성자함수"
위 예시 중 유심히 볼 부분은
p1 instanceof Person1의 결과가 true로 나왔단 점임
Person1의 프로토타입을 우리가 직접 교체하고constructor는 추가하지 않았지만,
instanceof 연산자는 constructor를 이용하여 생성자 함수를 찾는것이 아닌,
생성자 함수의 prototype에 바인딩된 객체가 프로토타입 체인 상에 존재하는지 확인함
그렇다고해서 constructor를 추가안하긴 찜찜하니 그냥 추가해 줄 듯
'js > 개발' 카테고리의 다른 글
js 재귀함수 & 콜백함수 (0) | 2023.02.12 |
---|---|
js 빌트인 객체 (0) | 2022.12.18 |
js 프로퍼티 어트리뷰트 (0) | 2022.12.03 |
js 함수내부에서의 this 바인딩 (0) | 2022.12.03 |
js Symbol 데이터 타입 (3) | 2022.10.17 |
댓글