[코어자바스크립트 스터디] - 6

Empu·2024년 8월 25일

javaScript

목록 보기
5/5

06. 프로토타입

프로토타입

  • 자바스크립트는 프로토타입 기반의 객체지향 프로그래밍언어이다.
  • 어떤 객체를 원형(prototype)?으로 삼고 이를 복제(참조)함으로써 상속과 비슷한 효과를 얻는다
  • 프로토타입은 ⇒ 유전자이다 (프로토타입에 무언가를 추가하면 자식들이 사용가능)

proto

  • prototype을 참조하는 객체.

모던 자바스크립트 Deep Dive

→ 내부 슬롯(ex [[Prototype]])과 내부 메서드(getter,setter)는 ECMAScript 사양에 정의된 대로 구현되어 자바스크립트 엔진에서 실제로 동작하지만 개발자가 직접 접근할 수 있도록 외부로 공개된 객체의 프로퍼티는 아니다.(직접적으로 접근 X)

why? → JavaScript의 안전성과 무결성을 유지하기 위해 설계됨?

  • prototype 객체 내부의 슬롯과 메서드들은 proto를 통해 간접적으로 접근 가능
  • 생략가능한 프로퍼티이다. (창조자가 그렇게 정함)
  • proto 접근자 프로퍼티는 상속을 통해 사용된다.
const person = {name: "Lee"};

//person 객체는 __proto__ 프로퍼티를 소유하지 않는다.
console.log(person.hasOwnProperty("__proto__")); //false

//__proto__프로퍼티는 모든 객체의 프로토타입 객체인 Object.prototype의 접근자 프로퍼티다.
console.log(Object.getOwnPropertyDescriptor(Object.prototype,"__proto__")); 
// { get: [Function: get __proto__], set: [Function: set __proto__], enumerable: false,configurable: true} -> 접근자 프로퍼티

//모든 객체는 Object.prototype의 접근자 프로퍼티 __proto__를 상속받아 사용할 수 있다. 정의될때 자동으로 __proto__가 설정
console.log({}.__proto__ === Object.prototype); //true

proto접근자 프로퍼티를 통해 프로토타입에 접근하는가? 왜 직접 x?

  • 상호 참조에 의해 프로토타입 체인이 생성되는 것을 방지하기 위함.
const parent = {};
const child = {};

//child의 프로토타입을 parent로 설정
child.__proto__ = parent;
//parent의 프로토타입을 child로 설정
parent.__proto__ = child;  //TypeError: Cyclic __proto__ value

→ 서로가 자신의 프로토타입이 되는 비정상적인 프로토타입 체인이 만들어지기 때문에 에러를 발생시킨다

  • 프로토타입 체인은 단방향 링크드 리스트로 구현되어야한다.
    • 순환참조하는 프로토타입 체인이 만들어지면 프로토타입 체인 종점이 존재하지 않기에 프로퍼티를 검색할때 무한 루프에 빠진다
    • 유효성 검사
      • 자기 참조 방지 → 객체는 자기자신을 프로토타입으로 설정x
      • 비객체 프로토타입 방지 → 프로토타입은 객체거나 null이어야 한다. 아니면 typeerror

constructor 프로퍼티

  • 생성자 함수의 프로퍼티인 prototype 객체 내부에는 constructor라는 프로퍼티가 있다.(proto도 마찬가지)
  • 단어 그대로 원래의 생성자 함수(자기자신)을 참조.
    • 굳이 왜? → 인스턴스로부터 그 원형이 무엇인지를 알 수있는 수단이기 때문에
//생성자 함수
function Person(name){
	this.name = name;
}

const me = new Person("Lee");
//me 객체의 생성자 함수는 Person이다.
console.log(me.constructor === Person); //true
  • constructor를 변경하더라도 참조하는 대상이 변경될 뿐 이미 만들어진 인스턴스의 원형이 바뀐다거나 데이터 타입이 변하는 것은 아님을 알 수 있다 → 어떤 인스턴스의 생성자 정보를 알아내기 위해 constructor 프로퍼티에 의존하는 게 항상 안전하지는 않은 것이다.

그림이해하기

new 연산자로 Constructor를 호출하면 instance가 만들어지는데, 이 instance의 생략 가능한 프로퍼티인 proto는 Constructor의 prototype을 참조한다.

  1. 자바스크립트는 함수에 자동으로 객체인 prototype 프로퍼티를 생성.
  2. 해당 함수를 생성자 함수로서 사용할 경우(new 연산자와 수행), 그로부터 생성된 인스턴스에는 숨겨진 프로피티인 proto가 자동생성
  3. 이 프로퍼티는 생성자 함수의 prototype 프로퍼티를 참조한다.
  4. proto가 생략가능하도록 구현돼 있기에 생성자 함수의 prototype에 어떤 메서드나 프로퍼티가 있다면 인스턴스에서도 마치 자신의 것처럼 해당 메서드나 프로퍼티에 접근할 수 있다.

프로토타입 체인

  • 프로토타입을 따라 단방향으로 연결된 연쇄 구조
  • 프로퍼티,메서드에 접근하려 할 때 해당 객체에 접근하려는 프로퍼티가 없으면 [[Prototype]] 내부 슬롯의 참조를 따라 자신의 부모 역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색한다.

메서드 오버라이딩

  • 원본을 제거하고 다른 대상으로 교체하는 것이 아니라 원본이 그대로 있는 상태에서 다른 대상을 그 위에 얹는 다는 것.
var Person = function(name){
	this.name = name;
}

Person.prototype.getName = function(){
	return this.name;
}

var iu = new Person("지금");
iu.getName = function(){
	return "바로 " + this.name;
}
console.log(iu.getName()); //바로 지금
  • 오버라이딩: 상위클래스가 가지고 있는 메서드를 하위 클래스가 재정의하여 사용하는 방식
  • 프로퍼티 섀도잉: 상속관계에 의해 프로퍼티가 가려지는 현상
  • 프로퍼티 삭제
delete iu.getName;

console.log(iu.getName()); //지금
  • 프로토타입 메서드가 아닌 인스턴스의 메서드가 삭제된다
    • 이와 같이 하위 객체를 통해 프로토타입의 프로퍼티를 변경 또는 삭제하는 것은 불가능하다.
      • get 엑세스는 허용되나 set엑세스는 허용되지 않는다.
      • 삭제하려면 프로토타입에 직접 접근

프로토타입 체이닝

  • 체인을 따라 프로퍼티나 메서드를 찾아가는 과정, 흐름
  • 프로토 타입 체이닝의 끝에는 어떤게 있을까? → object.prototype (모든 데이터 타입이 쓸 수 있는 범용 메서드) →
    • 예외적으로 Object.create()를 이용하면 접근 불가. .create는 proto가 없는 객체 생성하기 때문
    • 종점에서도 프로퍼티를 검색할 수 없는 경우 undefined를 반환.
profile
Life is a risk.

0개의 댓글