java, c++, javascript는 객체지향 언어입니다. java나 c++의 경우 class라는 개념을 지원하기 때문에 이를 사용하여 객체지향 프로그래밍이 가능합니다. 하지만 자바스크립트에는 class라는 개념이 없습니다. ECMA6에 class라는 문법이 추가되었지만, 이는 편의상 문법이 추가된거지 자바스크립트가 클래스 기반으로 바뀌었다는 것은 아닙니다.
그렇다면 자바스크립트는 어떻게 객체지향 프로그래밍이 가능할까요 ?
바로 프로토타입(Prototype) 사용하기 때문입니다. 프로토타입은 "원형"이라는 뜻으로 객체지향 프로그래밍의 한 형태이며 프로토타입으로 하여 복제의 과정을 통해 객체의 동작 방식을 다시 사용할 수 있습니다.
| 프로토타입 맛보기
프로토타입을 제대로 알아보기 전에 어떻게 쓰이는지 먼저 알아 봅시다.
자바스크립트에는 클래스가 없지만 생성자 함수와 new를 사용하여 클래스와 비슷하게 흉내낼 수 있습니다.
위의 코드에서 robot1과 robot2에는 각각 arm과 leg가 있는데, 둘다 공통적으로 가지고 있습니다. 만약 RobotMaker객체를 10개 만든다면 arm과 leg는 메모리에 20개가 할당되겠죠. 로봇은 다리와 팔이 2개이기 때문에 값이 변할 필요가 없습니다. 이 값을 각각의 객체가 가지고 있는 것보단 공통된 어떤곳에 놓고 참조한다면 메모리 낭비를 줄일 수 있을 것 같습니다.
그리고 만약, 로봇이 능력이라는 새로운 속성 추가한다면 어떻게 될까요 ? 각각의 객체에 추가해야 할까요? 만약 객체의 수가 1000개라면 그 수만큼 반복해야 할 것 입니다.
이런 문제를 프로토타입으로 해결할 수 있습니다.
기존의 경우 각각의 객체마다 하나씩 속성을 추가해주어야 했습니다. 하지만 RoomMaker.prototype에 속성을 추가하니, RoomMaker로 만든 객체에서 모두 이 속성에 접근할 수 있습니다. 생각해보면, robot1과 robot2은 어떤 "공통된 영역"의 값을 같이 참조하고 있습니다. 여기서 말한 "공통된 영역"이 프로토타입 입니다(정확히는 프로토타입은 prototype object와 prototype link을 모두 포함하는 개념입니다)
| 프로토타입 넌 누구냐
그럼 정확히 프로토타입은 무엇일까요 ? 일단은 위의 예제에서 대충 어떤 느낌인지는 알았습니다.
프로토타입을 알기 위해서는 prototype object와 prototype link를 모두 알고 있어야 합니다. 이 둘을 통틀어 프로토타입이라고 하기 때문입니다.
prototype object
prototype object는 자신이 다른 객체의 원형이 되는 객체입니다. 여기서 "자신"은 prototype object이며, 함수에서 prototype속성으로 접근할 수 있습니다. 이해가 안될 수도 있지만 천천히 읽어보면 어떤건지 감이 잡히실 겁니다.
먼저 함수를 생성하자마자 일어나는 일이 두가지가 있습니다.
1. 생성된 함수에 생성자(constructor) 자격 부여
함수는 생성자함수가(new 키워드로 객체를 생성할 수 있는 함수를 의미, RobotMaker) 됩니다. 보통, 생성자 함수의 이름은 일반적으로 대문자로 시작합니다.
2. prototype object의 생성 및 연결
함수를 생성하면 내부적으로 같이 prototype object도 같이 생성됩니다. 위에서 설명한 각각의 로봇 객체에 새로운 속성을 추가해야 할 필요가 없는 이유가 여기 있는데요, 일단 아래의 그림을 보겠습니다.
생성된 함수는 prototype이라는 속성을 가지고 있습니다. 여기 prototype이라는 속성을 통해서 prototype object에 접근할 수 있습니다. 크롬 개발자 도구로 prototype object가 어떻게 생겼는지 확인해 봅시다.
prototype object는 기본적으로 constructor, __proto__ 2가지 속성을 가지고 있습니다. constructor는 생성된 함수를 가리키고 있으며, __proto__는 밑에서 다시 설명하겠습니다. 여기서 constructor는 생성된 함수를 가리키고 있다고 했는데, 동적으로 함수의 속성을 추가할 수 있습니다.
prototype link
prototype link는 "객체원형에 대한 숨겨진 연결"을 의미합니다. 위의 사진에서 __proto__가 그 역할을 하고 있는데, 여담이지만 저도 개발자도구에서 __proto__가 자주 보여서 무엇인지 궁금했었는데, 이번에 프로토타입에 대해 공부하면서 정체(?)를 알게 되어서 너무 기분이 좋았습니다.
위의 코드에서 RobotMaker prototype object에 ability라는 속성을 추가하였고, RobotMaker생성자 함수에 존재하지 않는 속성값을 출력하고 있습니다. 생각을 해보면, robot1내부에는 arm, leg속성밖에 없기 때문에 undefined가 출력될 것 같지만 결과는 다릅니다. 어떻게 이런일이 가능할까요 ?
그 비밀은 __proto__에 있습니다. __proto__는 자신을 만들어낸 원형인 prototype object를 참조하는 숨겨진 링크를 의미합니다. __proto__는 프로토타입 체인의 핵심이며, ECMA의 스펙 [[Prototype]]이 자바스크립트로 노출될 것입니다. 모던 브라우저 개발자 도구에서도 디벙깅 편의상 노출하고 있지만 개발 코드에서 직접적으로 접근하는 것을 피해야 합니다. __proto__속성을 직접 사용하기 보다는 object.getPrototypeOf()를 이용해서 참조하시면 됩니다.
그렇다면 robot1객체는 어떻게 ability속성을 출력할 수 있는지 __proto__를 이용해서 알아봅시다.
1. robot1객체 내부에서 ability속성을 찾는다 ->없음
2. robot1객체 내부에 __proto__속성이 존재하는지 확인한다 ->있음
3. robot1객체의 __proto__속성이 참조하는 객체로 이동한다. ->RobotMaker함수의 prototype object로 이동
4. prototype object내부에 abilit속성이 있는지 확인한다 -> 있음
4. ability속성값을 return 한다.
이렇게 __proto__속성을 통하여 상위 프로토타입과 연결되어 있는 형태를 prototype chain 이라고 합니다.
위와 같은 과정으로 __proto__는 동작하게 됩니다. 그렇다면 한가지 궁금한 점은, prototype object의 __proto__는 어떤 객체를 참조하고 있을까요 ?
정답은 Object객체 입니다. 모든 객체의 최종 prototype이라고 하죠. __proto__를 타고 끝까지 가보면 결국에는 Object객체가 나오게 됩니다. Object가 끝판왕(?)이기 떄문에 __proto__속성이 없습니다. 만약 찾는 속성값이 Object에도 없으면 undefined를 return합니다. 그리고 prototype chain덕분에 모든 객체는 Object의 메서드에 접근할 수 있습니다.
| 프로토타입을 더 알아보기
1. 상속 흉내내기
자바스크립트는 __proto__속성을 사용하여 객체와 객체를 연결하고 한쪽 방향으로 상속을 받는 형태로 만들 수 있습니다. 객체와 객체를 연결하여 상속 받는 다는 의미는 다른 객체와 객체를 연결해 멤버 함수나 멤버 변수를 공유한다는 의미입니다. 이런 점을 이용해 자바스크립트에서는 상속과 비슷한 효과를 얻을 수 있습니다.
위에서 const obj1= {}은 "객레 리터럴"입니다. 이는 아래의 코드와 같은데 자바스크립트에서 기본적으로 제공하는 Object함수를 사용하여 객체를 생성한 것입니다.
const obj1 = new Object()
먼저 obj3의 prototype object는 obj2이고, obj2의 prototype object는 obj1입니다. 위의 예시는 prototype chain형태이며, __proto__속성을 사용해서 obj3은 obj1의 a속성에 접근할 수 있는 것입니다.
2. 오버라이드
프로토타입의 이런 속성을 이용하여 오버라이드 기능을 구현할 수 있습니다.
obj3는 mehtod메소드를 호출하고 있습니다. obj3에는 method가 없기 떄문에 obje2로 이동하고 obj2에는 method가 있기 때문에 obj1까지 올라가지 않고 emthod를 return 합니다. 자바스크립트에서는 이런 상황을 obj2의 method 메소드를 obj3가 오버라이드 했다고 합니다.
'javascript' 카테고리의 다른 글
[javascript] 클로저 (0) | 2020.05.08 |
---|---|
[javascript] this (0) | 2020.05.04 |
[javascript] 실행 컨텍스트 (0) | 2020.05.02 |
[javascript] undefined와 null (0) | 2020.05.02 |
[javascript] 데이터 타입 (0) | 2020.05.01 |