sharingStorage

모던 자바스크립트 19장 프로토타입 본문

Front-End/모던 자바스크립트 Deep Dive

모던 자바스크립트 19장 프로토타입

Anstrengung 2022. 6. 28. 10:06

객체지향 프로그래밍

객체지향 프로그래밍은 프로그램을 명령어 또는 함수의 목록으로 보는 전통적인 명령형 프로그래밍의 절차지향적 관점에서 벗어나 여러 개의 독립적 단위, 즉 객체의 집합으로 프로그래밍을 표현하는 프로그래밍 패러다임을 말한다.

 

객체지향 프로그래밍은 실세계의 실체를 인식하는 철학적 사고를 프로그래밍에 접목하려는 시도에서 시작하는데 실체는 특징이나 성질을 나타내는 속성을 가지고 있고 이를 통해 실체를 인식하거나 구별할 수 있다.

위와 같이 객체의 상태를 나타내는 데이터와 상태 데이터를 동작을 하나의 논리적인 단위로 묶어 생각하는 것이 객체지향 프로그래밍이다.

 

 

19.2 상속과 프로토타입

자바스크립트는 프로토타입을 기반으로 상속을 구현하여 불필요한 중복을 제거한다.

위의 코드에서 getArea() 메서드는 모든 인스턴스가 동일한 내용의 메서드를 사용하므로 하나만 생성하여 모든 인스턴스가 공유해서 사용하는 것이 바람직하다.

 

상속을 통해 불필요한 중복을 제거한 코드

 Circle 생성자 함수가 생성한 모든 인스턴스는 자신의 프로토타입, 즉 상위 객체 역할을 하는 Circle.prototype의 모든 프로퍼티와 메서드를 상속받는다.

 

 

19.3  프로토타입 객체

프로토타입 객체란 객체지향 프로그래밍의 근간을 이루는 객체 간 상속을 구현하기 위해 사용된다. 

프로토타입은 어떤 객체의 상위(부모) 객체의 역할을 하는 객체로서 다른 객체에 공유 프로퍼티를 제공한다.

 

 

19.3.1__proto__접근자 프로퍼티

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

빨간 박스로 표시한 것이 person 객체의 프로토타입인 Object.prototype이다. 

 

__proto__ 접근자 프로퍼티를 통해 간접적으로 프로토타입에 접근할 수 있다.

__proto__ 접근자 프로퍼티를 통해 프로토타입에 접근하는 이유는 상호 참조에 의해 프로토타입 체인이 생성되는 것을 방지하기 위해서이다.

 

 

19.3.2 함수 객체의 prototype 프로퍼티

함수 객체만이 소유하는 prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킨다.

일반 객체는 prototype 프로퍼티를 소유하지 않는다.

 

 

19.4 리터럴 표기법으로 생성된 객체의 생성자 함수와 프로토타입 

리터럴 표기법 생성자 함수 프로토타입
객체 리터럴 Object Object.prototype
함수 리터럴 Function Function.prototype
배열 리터럴 Array Array.prototype
정규 표현식 리터럴 RegExp RegExp.prototype

 

19.5 프로토타입 생성 시점

프로토타입은 생성자 함수가 생성되는 시점에 더불어 생성된다.

 

생성자 함수로서 호출할 수 있는 함수 즉 constructor는 함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성된다.

생성자 함수로서 호출할 수 없는 함수 즉 non-constructor는 프로토타입이 생성되지 않는다.

 

 

프로토타입 체인

자바스크립트는 객체의 프로퍼티에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티가 없다면 [[Prototype]] 내부 슬롯의 참조를 따라 자신의 부모 역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색한다. 이를 프로토타입 체인이라 한다. 프로토타입 체인은 자바스크립트가 객체지향 프로그래밍의 상속을 구현하는 메커니즘이다.

 

모든 객체는 Object.prototype을 상속받으며 이것은 프로토타입 체인의 종점이라 한다.

 

스코프 체인에서 먼저 식별자를 검색한 후 객체의 프로토타입 체인에서 메서드를 검색한다.

이처럼 스코프 체인과 프로토타입 체인은 서로 협력하여 식별자와 프로퍼티를 검색하는데 사용된다.

 

19.10 instanceof 연산자

instanceof 연산자는 우변의 생성자 함수의 prototype에 바인딩된 객체가 좌변의 객체의 프로토타입 체인 상에 존재하면 true로 평가되고 그렇지 않은 경우에는 false로 평가된다.

 

instanceof 연산자를 함수로 구현한 코드

※여기서 90번째 줄 return의 의미는 prototype===constructor.prototype을 true로 반환할 수 있으면 이를 반환하고 false일 경우  || 의 뒷 부분을 반환한다는 의미이다.

 

 

19.11 직접 상속

19.11.1 Object.create에 의한 직접 상속

Object.create 메서드는 명시적으로 프로토타입을 지정하여 새로운 객체를 생성한다.

Object.create 메서드의 첫 번째 매개변수에는 생성할 객체의 프로토타입으로 지정할 객체를 전달하고 두 번째 매개변수에는 생성할 객체의 프로퍼티 키와 프로퍼티 디스크립터 객체로 이뤄진 객체를 전달한다.

두번째 인수는 옵션이다.

이렇게 Object.create 메서드를 사용했을 때의 장점은 다음과 같다.

  • new연산자가 없어도 객체를 생성할 수 있다.
  • 프로토타입을 지정하면서 객체를 생성할 수 있다.
  • 객체 리터럴에 의해 생성된 객체도 상속받을 수 있다.

ESLint에서는 hasOwnProperty, peopertyIsEnumerable 같은 Object.prototype의 빌트인 메서드를 객체가 직접 호출하는 것을 권장하지 않는다. 그 이유는 Object.create 메서드를 통해 프로토타입 체인의 종점에 위치하는 객체를 생성할 수 있기 때문이다. 프토토타입 체인의 종점에 위치한 객체는 Object.prototype의 빌트인 메서드를 사용할 수 없다.

 

따라서 이러한 에러를 발생시킬 위험을 없애기 위해 아래와 같이 간접적으로 호출하는 것을 권장한다.

console.log(Object.prototype.hasOwnProperty.call(obj,'a'));

 

 

19.11.2 객체 리터럴 내부에서 __proto__에 의한 직접 상속

 

 

19.12 정적 프로퍼티/메서드

정적 프로퍼티/메서드는 생성자 함수로 인스턴스를 생성하지 않아도 참조/ 호출할 수 있는 프로퍼티/ 메서드를 말한다.

 

 

19.13 프로퍼티 존재 확인

 

19.13.1 in 연산자

in연산자는 객체 내에 특정 프로퍼티가 존재하는지 여부를 확인한다.

 

※ES6에서 도입된 Reflect.has 메서드를 사용할 수도 있다. (in과 동일하게 동작)

 

 in연산자는 확인 대상 객체 프로퍼티 뿐만 아니라 객체가 상속받은 모든 프로토타입의 프로퍼티를 확인하므로 주의가 필요하다.

위 예시에서 for in문에서 toString같은 프로퍼티가 열거되지 않는 이유는 toString메서드가 열거할 수 없도록 정의돼있는 프로퍼티이기 때문이다. 다시말해 Object.prototype.string 프로퍼티의 프로퍼티 어트리뷰트의 [[Enumerable]]값이 false이기 때문이다.

 

 

for .. in 문은 객체의 프로토타입 체인 상에 존재하는 모든 프로토타입의 프로퍼티 중에서 프로퍼티 어트리뷰트의 Enumerable값이 ture인 프로퍼티를 순회하며 열거한다.

 

for .. in 문은 객체 자신의 고유프로퍼티뿐 아니라 상속받은 프로퍼티도 열거한다. 따라서 객체 자신의 고유 프로퍼티만 열거하기 위해서는 Object.keys/values/entries 메서드를 사용하는 것을 권장한다.

 

Object.keys메서드는 객체 자신의 열거 가능한 프로퍼티 키를 배열로 반환한다.

Object.values 메서드는 객체 자신의 열거 가능한 프로퍼티 값을 배열로 반환한다. (ES8 도입)

Object.Entries 메서드는 객체 자신의 열거 가능한 프로퍼티 키와 값의 쌍의 배열을 배열에 담아 반환한다. (ES8 도입)

 

 

 

Reference

  • 모던 자바스크립트 Deep Dive 이웅모 지음
Comments