본문 바로가기

TIL

JS. 프로토타입

일단 프로토타입 시작하기 전에 밑에 글부터 읽고 오면 좋을 거 같다 너무 재미있게 읽은 글이다.

https://medium.com/@limsungmook/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%99%9C-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85%EC%9D%84-%EC%84%A0%ED%83%9D%ED%96%88%EC%9D%84%EA%B9%8C-997f985adb42

 

자바스크립트는 왜 프로토타입을 선택했을까

프로토타입으로 검색하면 으레 나오는 서두처럼 저 또한 자바스크립트를 처음 접했을 때 가장 당황스러웠던 게 프로토타입이었습니다.

medium.com

그리고 정리를 한번 하고 마지막에 위의 글을 한번더 읽으면 좋을 거 같다. 나는 역시 자바스크립트 DeepDive를 바탕으로 정리하려고 한다. 가보자

자바스크립트도 보면 Class라는 걸 지원해서 그냥 내가 알던 자바나 C++ 같은 객체 지향 언어로 생각했지만, 생각보다 흥미로운 친구였다. 찾아보면 자바스크립트는 프로토타입 기반 객체지향 프로그래밍 언어라고 한다. 그래서 자바스크립트는 클래스 따로 선언하지 않고 객체를 생성할 수 있다. 그에 대한 자세한 방법은 밑에를 참조하자

https://poiemaweb.com/js-object#2-%EA%B0%9D%EC%B2%B4-%EC%83%9D%EC%84%B1-%EB%B0%A9%EB%B2%95

 

Object | PoiemaWeb

자바스크립트는 객체(object)기반의 스크립트 언어이며 자바스크립트를 이루고 있는 거의 “모든 것”은 객체이다. 원시 타입(Primitives)을 제외한 나머지 값들(함수, 배열, 정규표현식 등)은 모두

poiemaweb.com

자바스크립트의 모든 객체는 자신의 부모 역할을 담당하는 객체와 연결되어 있어서 부모 객체의 프로퍼티 또는 메서드를 상속받아서 사용할 수 있게 한다. 이러한 부모 객체를  프로토타입 객체라고 한다. 

ECMAScript spec에서는 자바스크립트의 모든 객체는 [[Prototype]]이라는 인터널 슬롯(internal slot)를 가진다. [[Prototype]]의 값은 null 또는 객체이며 상속을 구현하는 데 사용된다. [[Prototype]] 객체의 데이터 프로퍼티는 get 액세스를 위해 상속되어 자식 객체의 프로퍼티처럼 사용할 수 있다. 하지만 set 액세스는 허용되지 않는다.라고 되어있다.

[[Prototype]]의 값은 Prototype(프로토타입) 객체이며 __proto__ accessor property로 접근할 수 있다. __proto__ 프로퍼티에 접근하면 내부적으로 Object.getPrototypeOf가 호출되어 프로토타입 객체를 반환한다.

모든 객체는 따로 프로토타입 지정 안 해주면 example.__proto__ 가 Object.prototype이다.  근데 여기서 헷갈리는게[[prototype]]이랑 prototype프로퍼티랑 뭐가 다른지 모르겠다. prototype 프로퍼티는 함수 객체만 소유하게 되고 [[prototype]]은 모든 객체가 갖는다.

책에서는 다음과 같이 정리한다.

[[Prototype]]

  • 함수를 포함한 모든 객체가 가지고 있는 인터널 슬롯이다.
  • 객체의 입장에서 자신의 부모 역할을 하는 프로토타입 객체를 가리키며 함수 객체의 경우 Function.prototype를 가리킨다. 그 이유에 대해서는 4.2 생성자 함수로 생성된 객체의 프로토타입 체인을 참조하기 바란다.

prototype 프로퍼티

  • 함수 객체만 가지고 있는 프로퍼티이다.
  • 함수 객체가 생성자로 사용될 때 이 함수를 통해 생성될 객체의 부모 역할을 하는 객체(프로토타입 객체)를 가리킨다.

이제 다음으로 Constructor 프로퍼티에 대해 알아보자. 프로토타입 객체는 constructor 프로퍼티를 갖는다. 이 constructor 프로퍼티는 객체의 입장에서 자신을 생성한 객체를 가리킨다.

function Person(name) {
  this.name = name;
}

var foo = new Person('Lee');

// Person() 생성자 함수에 의해 생성된 객체를 생성한 객체는 Person() 생성자 함수이다.
console.log(Person.prototype.constructor === Person);

// foo 객체를 생성한 객체는 Person() 생성자 함수이다.
console.log(foo.constructor === Person);

// Person() 생성자 함수를 생성한 객체는 Function() 생성자 함수이다.
console.log(Person.constructor === Function);

마지막으로 알아야 하는것중에 하나가 프로토 타입 체인이라는 것이다.

자바스크립트는 특정 객체의 프로퍼티나 메서드에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티 또는 메서드가 없다면 [[Prototype]]이 가리키는 링크를 따라 자신의 부모 역할을 하는 프로토타입 객체의 프로퍼티나 메서드를 차례대로 검색한다. 이것을 프로토타입 체인이라 한다.

그럼 객체생성 방식별 프로토타입 체인을 알아보면서 이번 글을 끝내겠다.

먼저 객체 리터럴 방식인데 , 객체 리터럴 방식은 내부적으로 Object() 생성자 함수를 사용하여 객체를 만들기 때문에 그 객체의 프로토타입 객체는 Object.prototype이다.

객체 리터럴 방식으로 생성된 객체의 프로토타입 체인

다음으로 생성자 함수로 생성된 객체의 프로토타입 체인을 보자. 함수정의는 함수 선언식, 함수 표현식, 생성자 함수를 사용한다. 결론적으로 말하면 함수 선언식, 함수 표현식 모두 함수 리터럴 방식을 사용한다. 함수 리터럴 방식은 Function() 생성자 함수로 함수를 생성하는 것을 단순화한 것이다.

 

즉, 3가지 함수 정의 방식은 결국 Function() 생성자 함수를 통해 함수 객체를 생성한다, 따라서 어떠한 방식으로 함수 객체를 생성하여도 모든 함수 객체의 prototype 객체는 Function.prototype이다. 생성자 함수도 함수 객체이므로 생성자 함수의 prototype 객체는 Function.prototype이다.

생성자 함수로 생성된 객체의 프로토타입 체인

오늘은 자바스크립트에서 프로토타입에 대한 약속을 정리하는 부분이어서 책의 내용 위주로 정리했다. 근데 맨 처음 글 같은 경우에는 왜 프로토타입을 선택했는지가 나와있고,

간단히 결론만 내보면 크게 2가지다. 클래스와 다르게 자바스크립트의 프로토타입은 내가 특정한 정의에 의해서 객체를 만들기보다는 비슷한 친구끼리 나뉘고 다른 게 있으면 추가되고 또 그걸 공유하고 하는 거 같다. 그리고 또한 가지 중요한 점은 자바스크립트의 전반적인 문법은 문맥에 따라 결정된다는 것이다. 그래서 this의 경우도 달라지고, 호이스팅 같은 현상도 렉시컬 스코프에 따라 달라지게 설계되어있다.  실행 컨텍스트만 봐도 컨텍스트를 얼마나 중요하게 생각하고 개발자들이 만든 지 알 거 같다.