[TIL] OOP와 JavaScript Prototype

김형주·2021년 4월 9일
0

오전에는 객체지향 프로그래밍이라는 것을 나만의 방식으로 분석하고 이해하는 시간을 가지고 포스팅했다. 누구나 본인이 처음 마주한 것을 이해하려 할때는 자신만의 방식으로 이해하는 것이 가장 효율적이라는 말에 찬성한다. 이전까지 머릿속에서 맴돌기만 하던 것이 조금은 쉽게 이해될 수 있는 시간이었다. 얼추 이해한 것 같을 때, 글로 정리하는 것이 이해에 얼마나 큰 도움이 되는지 알게 해주는 시간이었다. 앞으로 TIL을 작성할 때에는, 개념을 적는 것보다 그 개념을 통해서 알게된 것이나 더 삽질해서 알게된 내용들을 적는 것이 훨씬 더 크게 도움이 될 거라는 생각이 들었다.

시작하기에 앞서

지금부터 적어나가고자 하는 내용은 객체지향 프로그래밍의 방법론을 닮은 JavaScript의 Prototype기반의 OOP에 대해서 정리하려고 하는 글이다. 글을 쓰는 와중에 실제 내용과 틀린 부분이 많을지도 모르지만, 하나하나 배워나가는 과정이기에 이해한대로 적다보면 언젠가 더 익숙해졌을 때에 이 글을 수정하게 되는 날이 오리라 믿어 의심치 않는다.

OOP와 JavaScript Prototype

나는 항상 쓰기에 앞서, 용어를 미리 이해하고 넘어가는 것을 앞으로 주요한 방법으로 사용하는 것이 좋을 것 같다는 생각이 들어서 글을 쓸 때에는 항상 영어단어의 의미를 먼저 파악하고 항상 글을 시작하는 것으로 오늘부터 결정하겠다.

참고로 영어 단어 뜻을 몰라서 작성하는 것은 아니다. 그냥 명시적으로 해두는 것이 나중에 이해하는 것에 있어서도 빠르게 의미로 연결되기 때문이다.


Prototype (명사)
원형(原型), 시험제작원형

말그대로 프로토타입은 원형(原型)을 뜻한다. 어떤 상품을 제작할 때에 가장 맨처음 만든 테스터 제품을 프로토타입이라고 부르는 이유는 바로 그런 것이다. 뭔가를 만들기 위한 틀이 되는 대상이며, 가장 초기에 만들어지는 무언가다. 기본적으로 JavaScript는 이러한 Prototype을 기반으로 이루어진 OOP 체계를 가지고 있다. 쉽게 말하면 인간의 최상단의 Prototype은 아마도 아미노산일 것이다. 지구가 처음 만들어지고 생명이 시작된 근원은 아미노산이었으니까.

간단하게 구글링을 통해 가져온 가계도 다이어그램이다. 이 그림이 아무래도, 프로토타입의 개념을 이해하는데에 크게 도움이 될거라는 생각에서 가져왔다. 위 이미지를 보면 부모 사이의 자녀는 밑으로 계속해서 뻗어나온다. 밑의 자식의 부모는 바로 위에 있고, 계속해서 올라가면 증조할머니, 증조할아버지까지 이어진다. 이 그림에서 가장 위에 있는 것이, 나 자신의 최고 조상이 된다.

이걸 JavaScript에서 보면 위처럼 표현할 수 있을텐데, 총 3번의 상속을 받은 클래스가 있다고 치자. 이 클래스는 이름은 알 수 없지만, 그 원형인 prototype을 3번 올라가보면 최고위의 prototype을 만날 수 있게 된다. 사람은 가계도에서 내려오면서 조상의 특징이나 생김새를 닮아오게 되는데 Prototype 역시 그런 특징들을 닮는 것과 비슷한 상속을 한다.

Prototype 객체

위의 내용을 코드를 통해 확인해보자.

const developer = {
  name: 'kim',
  age : 29
}
console.log(developer.hasOwnProperty('name')); // true

굳이 class를 만들어서, instance를 생성하지 않더라도 Javascript에서는 변수에 할당함으로서 객체를 생성할 수 있다. 생성한 developer 객체에는 어디에도 hasOwnProperty()라는 메소드를 발견할 수 없지만, 콘솔결과를 받을 수 있다.

콘솔창에 객체를 찍어보면 알 수 있는데, __proto__ 라는 속성을 가지고 있다. 이 __proto__를 접근하게 되면 내부적으로 Object.getPrototypeOf가 호출되며 프로토타입 객체를 반환한다. 위의 경우에는 따로 상속받은 Prototype이 없기 때문에 바로 위에 있는 Object() 원형 프로토타입이 반환된다.

__proto__속성은 자신의 부모객체인 Object.prototype을 가리키고 있다.

console.log(developer.__proto__ === Object.prototype); // true

객체(class와 fucntion도 객체에 포함된다.)를 생성할 때, prototype이 결정된다. 이후에 만약 developer.__proto__ = Person을 입력하게되면, developer의 prototype은 Person을 가리키는 것으로 변경되며, 부모 객체를 바꿀 수 있다는 것을 의미한다. 이를 이용해서 동적으로 상속받을 수 있는 객체 상속"처럼" 사용할 수 있다.

[[Prototype]] vs prototype property

모든 객체는 자기 자신의 프로토타입 객체를 가리키는 [[Prototype]]인터널 슬롯(internal slot)을 가지고 있다. 함수도 객체이므로 인터널 슬롯을 가지고 있다. 근데 함수 객체는 일반 객체와 달리 prototype이라는 속성도 따로 가지고 있다.

prototype !== [[prototype]]
둘다 프로토타입 객체를 가리키지만 다른 것이다.

  • [[Prototype]] = __proto__
    • 함수를 포함한 모든 객체가 가지고 있는 인터널 슬롯이다.
    • 객체의 입장에서 자신의 부모역할을 하는 프로토타입 객체를 가리키며, 함수 객체의 경우 Function.prototype을 가리킨다.
  • prototype 속성
    • 함수 객체만 가지고 있는 프로퍼티이다.
    • 함수 객체가 생성자로 사용될 때 이 함수를 통해 생성될 객체의 부모 역할을 하는 객체(프로토타입 객체)를 가리킨다.
    • 함수 객체는 본인의 생성자 함수로 생성된 것이 아니라 Function()생성자 함수로 생성되었기 때문에 본인을 참조할 방법이 필요해 있는 것이다.

constructor 속성

프로토타입의 객체는 constructor를 갖는다. 본인을 생성한 객체를 가리킨다. 원본 프로토타입(함수 객체명)을 가리킨다고 보면된다.

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

다음과 같이 Person 생성자 함수를 만들면, Person을 통해 만들어지는 인스턴스의 constructor는 Person 함수가 되고, Person 자신의 프로토타입의 생성자 함수도 Person함수가 된다. 하지만 Person생성자함수는 함수이므로 자신의 constructor는 Function이 된다. 여기에서 알 수 있는 사실은 Function() 원본 프로토타입 객체 역시 생성자 함수라는 것.

프로토타입 체인

이부분은 JS를 공부할 때 이미 공부한 내용이지만, 좀 더 상세히 알게되었다.
자바스크립트는 특정 객체 안의 속성값이나 메소드를 접근하려고 할때 해당 객체에 접근하려는 속성이나 메소드가 없다면 [[prototype]]이 가리키는 링크를 따라 자신의 부모객체에서 찾는다. 또 없으면 부모객체의 [[prototype]]을 찾아가 찾는다. 결국 중첩 상속을 받아와도, 모든 메소드나 값에 접근이 가능하다는 뜻이다.

위의 사진과 같은 방식으로 메소드나 속성을 차례차례 찾아나간다.

객체 생성방식

객체 생성 방식은 3가지가 있다.

  1. 객체 리터럴(말그대로 객체)
    const developer = {
     name : 'kim' 
    }

어차피 이렇게 불러도, Object() 생성자 함수로 객체를 생성함.

  1. 생성자 함수
    함수 선언식
    function Person(){ }
    const newPerson = new Person();
    //
    //
    함수 표현식 => 익명함수로 할당해도, 기명함수로 변경됨
    const people = function(number){ }

Person이나 people는 생성자 함수이므로, prototype 속성을 가지게됨.

Person.prototype === Person //true
personMaker.prototype === personMaker//true

  1. Object() 생성자 함수
    const newObject = new Object();

정리중

profile
만물에 관심이 많은 잡학지식사전이자, 새로운 도전을 꿈꾸는 주니어 개발자 / 잡학지식에서 벗어나서 전문성을 가진 엔지니어로 거듭나자!

0개의 댓글