자바스크립트 셀프 QnA(5): Not My Type 🥶 프로토타입 🥵

9rganizedChaos·2021년 10월 25일
0
post-thumbnail

(<자바스크립트 셀프 QnA> 시리즈에 작성된 포스팅들은 각 주제에 해당하는 <모던 자바스크립트 딥다이브> 챕터를 읽으며 요약한 내용입니다. 더 자세한 내용은 <모던 자바스크립트 딥다이브>를 참고해주세요.)

모던 자바스크립트 딥다이브

Q1 객체지향 프로그래밍에 대해 설명해주세요.

  • 자바스크립트는 명령형, 함수형, 프로토 타입 기반 객체지향 프로그래밍을 지원하는 멀티 패러다임 프로그래밍언어이다.
  • 모쪼록 자바스크립트는 객체 기반 프로그래밍 언어이고, 자바스크립트를 이루고 있는 거의 모든 것이 객체다. (원시 타입 값들 제외)

  • 객체지향 프로그래밍은 프로그램을 명령어 또는 함수의 목록으로 보는 전통적인 명령형 프로그래밍의 절차지향적 관점에서 벗어나 여러 개의 독립적 단위, 즉 객체의 집합으로 프로그램을 표현하려는 패러다임을 말한다.
  • 이 때 객체란 상태를 나타내는 데이터(프로퍼티)와 상태 데이터를 조작할 수 있는 동작(메서드)을 하나의 논리적인 단위로 묶은 복합적인 자료구조이다.
  • 각 객체는 고유한 기능을 수행하면서 다른 객체와 관계성을 갖는다. 다른 객체의 상태 데이터나 동작을 상속받아 사용하기도 한다.

Q2 prototype과 __proto__에 대해 설명하세요.

  • 어떤 객체의 프로퍼티 또는 메서드를 다를 개게가 상속받아 그대로 사용하는 것을 말한다.
  • 생성자 함수는 동일한 구조를 갖는 객체를 여러개 생성할 때 유용한데, 문제는 인스턴스를 생성할 때마다 같은 메서드를 생성하다보면 불필요하게 메모리를 낭비하게 된다.
  • 불필요한 중복을 제거하며 상속을 하기 위해 자바스크립트는 프로토타입을 기반으로 상속을 구현한다.
  • 이제 생성자 함수들은 prototype이라는 속성(객체)에 데이터를 저장하고, 인스턴스들은 자신의 부모 객체 prototype의 모든 프로퍼티와 메서드를 상속받는다.
  • 즉, 인스턴스는 별도의 구현 없이 상위 객체인 프로토타입의 자산을 공유하여 사용할 수 있다.

  • 모든 객체는 [[Prototype]]이라는 내부슬롯을 가지며, 이 내부 슬롯의 값은 프로토타입의 참조다.
  • 또한 모든 객체는 하나의 프로토타입을 갖는다. 그리고 모든 프로토타입은 생성자 함수와 연결되어 있다.

  • 모든 객체는 __proto__ 접근자 프로퍼티를 통해 자신의 프로토타입, 즉 [[Prototype]] 내부 슬롯에 간접적으로 접근할 수 있다.

  • 사실 내부 슬롯은 프로퍼티가 아니다. 그래서 접근자 프로퍼티를 통해 간접적으로 접근할 수 있다는 것이다. __proto__ 접근자 프로퍼티는 이 자체로 값을 갖는 것이 아니다. 이들은 다른 데이터 프로퍼티의 값을 일거나 저장할 때 사용하는 접근자 함수 [[Get]], [[Set]] 프로퍼티 어트리뷰트로 구성된 프로퍼티다.

  • __proto__ 는 객체가 직접 소유하는 게 아닌, Object.prototype의 프로퍼티이다.
  • 프로토타입에 접근하기 위해 접근자 프로퍼티를 사용하는 이유는 상호참조에 의해 프로토타입 체인이 생성되는 것을 방지하기 위함이다. 프로토타입은 단방향 링크드 리스트로 구현되어야 한다. 순환참조 프로토타입 체인이 만들어지면 프로퍼티를 검색할 때 무한루프에 빠질 수 있다.
  • 모쪼록 __proto__를 코드에서 직접 사용하는 것은 지양하는 편이 좋다.
  • 프로토타입의 참조를 취득하고 싶다면 Object.getPrototypeOf를, 프로토타입을 교체하고 싶다면 Object.setPrototypeOf를 사용하도록 하자.

  • 함수 객체만이 소유하는 prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킨다.
  • 생성자 함수로서 호출할 수 없는 함수, 화살표함수와 ES6 메서드 축약 표현으로 정의한 메서드는 prototype 프로퍼티를 소유하지 않으며 프로토타입도 생성하지 않는다.
  • 애초에 객체를 생성하지 않는 일반함수의 prototype 프로퍼티는 아무 의미가 없다.
  • 모든 객체가 갖고 있는 __proto__ 접근자 프로퍼티와 함수 객체가 갖고 있는 prototype 프로퍼티는 결국 동일한 프로토타입을 가리킨다.

Q3 Constructor는 무엇인가요?

  • 모든 프로토타입은 constructor 프로퍼티를 갖는다.
  • constructore 프로퍼티는 prototype프로퍼티로 자신을 참조하고 있는 생성자 함수를 가리킨다.

  • 생성자 함수에 의해 생성된 인스턴스는 프로토타입의 constructor 프로퍼티에 의해 생성자 함수와 연결된다.
  • 프로토타입과 생성자함수는 단독으로 존재할 수 없고 언제나 쌍으로 존재한다.

Q4 객체 생성 방식에 따라 프로토타입은 어떻게 달라지나요?

  • 기본적으로 객체는 세부적인 생성 방식에 차이는 있지만 결국 모두 추상 연산 OrdinaryObjectCreate에 의해 생성된다는 공통점이 존재한다.
  • 해당 연산을 사용할 떄 우리는 생성할 객체의 프로토타입을 인수로 전달해주어야 한다.
  • 즉, 프로토타입은 추상연산 OrdinaryObjectCreate에 전달하는 인수에 의해 결정된다.

  • 객체 리터럴에 의해 생성되는 객체의 프로토타입은 Object.prototype이다.
  • Object 생성자 함수에 의해 생성되는 객체의 프로토타입은 Object.prototype. 객체리터럴과 동일하지만, 객체리터럴은 객체 리터럴 내부에 프로퍼티를 추가하지만, Object 생성자 함수는 일단 빈 객체를 생성하고 프로퍼티를 추가한다는 차이가 있다.
  • new 연산자와 함께 생성자 함수를 호출해 인스턴스를 생성하면, 생성자 함수의 prototype에 바인딩 되어 있는 객체가 인자로 전달된다.

Q5 프로토타입 체인이란 무엇인가요?

  • 자바스크립트는 객체 프로퍼티에 접근하려고 할때 해당 객체에 접근하려는 프로퍼티가 없다면 [[Prototype]] 내부 슬롯의 참조를 따라 자신의 부모 역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색한다. 이를 프로토타입 체인이라 한다.
  • Object.prototype은 언제나 프로토타입 체인의 종점이다.

Q6 오버라이딩과 프로퍼티 섀도잉에 대해 설명하세요.

  • 프로토타입 프로퍼티와 같은 이름의 프로퍼티를 인스턴스에 추가하면 프로토타입 체인을 따라 프로토타입 프로퍼티를 검색하여 프로토타입 프로퍼티를 덮어쓰는 것이 아니라 인스턴스 프로퍼티로 추가된다.

  • 이 때, 인스턴스 메서드 sayHello는 프로토타입 메서드 sayHello를 오버라이딩 했고, 프로토타입 메서드 sayHello는 프로퍼티 섀도잉 된 것이다!
  • 삭제하는 경우도 마찬가지이다. 프로토타입 메서드가 삭제되는 것이 아니라, 인스턴스 메서드가 색제된다. 사실 하위 객체를 통해 프로토타입의 프로퍼티를 변경 또는 삭제하는 것은 불가능하다.
  • 프로퍼티를 변경, 삭제 하려면 프로토타입 체인으로 접근하는 것이 아니라 프로토타입에 직접 접근해야 한다!

Q7 instanceof 연산자

  • 우변의 생성자 함수의 prototype에 바인딩된 객체가 좌변 객체의 프로토타입 체인 상에 존재하면 true, 그렇지 않으면 false를 리턴한다.
  • 기억해야 할 것은 우변의 생성자함수 자체만 탐색하는 것이 아니라, 생성자 함수의 prototype에 바인딩된 객체가 프로토타입 체인상에 존재하는가를 확인하는 것이다!

Q8 프로퍼티 존재 확인

  • in 연산자: 객체 내에 특정 프로퍼티가 존재하는지 여부를 확인! 중요한 점은 확인 대상 객체의 프로퍼티 뿐만이 아니라 확인 대상 객체가 상속받은 모든 프로토타입의 프로퍼티를 확인한다.

  • ES8에서 도입된 Object.entries 메서드를 사용하면 객체 자신의 열거 가능한 프로퍼티 키와 값의 쌍의 배열을 배열에 담아 반환한다.

profile
부정확한 정보나 잘못된 정보는 댓글로 알려주시면 빠르게 수정토록 하겠습니다, 감사합니다!

0개의 댓글