자바스크립트 셀프 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개의 댓글

관련 채용 정보