책 읽다가 코딩하다 죽을래

자바스크립트 prototype에 대해 지금 같이 알아볼까? 본문

코딩/자바스크립트

자바스크립트 prototype에 대해 지금 같이 알아볼까?

ABlue 2021. 9. 29. 09:32

🧾 이 강의는 시리즈 별로 되어있습니다.

 

이 강의를 읽은 후에 확인하세요!

prototype으로 배워보는 메소드 상속 및 동작 원리[클릭]

prototype chaining에 대해 알아봅시다

 

이 글은 인프런 정재남 강사님의 JS Flow 강의를 기반으로 하여 작성하였습니다.

인프런 JS Flow 강의 보러 가기[클릭]

 

견우(Object.prototype)와 직녀(Object 인스턴스)를 잇는 연결고리는 오작교(인스턴스.[[prototype]])이다.

 

📚 프로토타입(Prototype)이란?

 

JavaScript는 흔히 프로토타입 기반 언어(prototype-based language)라 불립니다. 모든 객체들이 메소드와 속성들을 상속받기 위한 템플릿으로써 프로토타입 객체(prototype object)를 가진다는 의미입니다. 프로토타입 객체도 또다시 상위 프로토타입 객체로부터 메소드와 속성을 상속받을 수도 있고 그 상위 프로토타입 객체도 마찬가지입니다. 이를 프로토타입 체인(prototype chain)이라 부르며 다른 객체에 정의된 메소드와 속성을 한 객체에서 사용할 수 있도록 하는 근간입니다.

 

- MDN 공식 문서 - prototype에 관한 설명중에서..[클릭시 해당페이지 이동]

 

 

배열 [1,2,3,4,5]를 map 메소드를 이용하면 다음과 같이 배열 원소의 값이 차례대로 나옵니다.

 

우리는 여기서 map메소드를 만든 적이 없는데 어떻게 사용할 수 있을까요?라는 궁금점이 생깁니다.

 

😒 그건 자바스크립트 내장되어 있는 배열 메소드를 사용한 거잖아요.

 

물론 그것도 맞는 말이지만 정확한 원리를 알기 위해서는 prototype을 이해하셔야 합니다.

prototype은 앞에 MDN설명처럼 JS에서 가장 중요한 기본 개념 중 하나이며 실무 면접에서 자주 물어보는 개념 중 하나입니다.

 

 

📚 prototype 구조

 

prototype의 구조는 마치 삼각형과도 같습니다.

이게 무슨 뜻이냐면

 

생성자 함수를 통해 인스턴스를 만들게 된다면

 

 

 

 

생성자 안에 prototype이란 속성이

인스턴스__proto__으로 전달됩니다.

즉 이 prototype__proto__은 같은 객체를 참조하게 됩니다.

 

하지만 __proto__는  인스턴스의 정보를 읽을 수 있을 뿐이지 실제 동작상엔 인스턴스와 거의 동일 해지며 

이런 식으로 삼각형의 모형처럼 나타낼 수 있다.


예로 들어서 설명하겠습니다.

 

JS의 Array이란 데이터 타입에는 length 등의 속성을 갖고 isArray(), from() 등의 메소드들이 정의되어 있습니다.

어떤 데이터 타입에는 사용할 수 있는 속성과 메소드들이 정의되어 있는지 알 수 있는 것은 바로 prototype입니다.

 

 

크롬 개발자 도구를 통하여 본 prototype의 내용들입니다.

여기서 각 속성과 메소드들의 정보들이 담겨있습니다.

 

자 그럼 여기서 배열 [1,2,3]을 new Array(생성자 함수)를 통하여 만들어봅시다.

 

마치 이런식으로 말이죠

 

생성자 함수로 생성한 인스턴스는 Array라는 타입을 갖게 됩니다.

이 인스턴스 역시 length 등의 속성과 map(), push() 등 여러 메소드를 갖고 있습니다.

[[prototype]]이란 속성이 있는데 이걸 살펴보면

 

우리가 Array의 prototype에서 봤던 length, push(), map() 함수들을 볼 수 있습니다.

 

 

즉 Array의 prototype이 인스턴스의 [[prototype]] 과 연결되어 있는 것입니다.

이 둘은 같은 객체입니다.

 

👭 prototype과 생성자의 관계

 

Array의 prototype에는 constructor(생성자)가 있는데 이는 또다시 자기 자신을 가리키고 있습니다.

하늘색 네모칸은 배열 자기 자신의 정보를 담고 있는 것들이고

그 밖에 있는 것들은 자기 자신이 사용할 수 있는 메소드를 담고 있다고 생각하시면 됩니다.

(여기서 나 자신이란 배열(Array)의 생성자 함수입니다. 헷갈리지 마세요!)

 

즉 자신의 prototype의 생성자는 나 자신을 가리킨다고 보시면 됩니다

 

그런데 여기서 Array 생성자를 통하여 만들어진 객체의 생성자도 나 자신을 가리키고 있습니다. 

 

이게 결국에는

 

Array.prototype.constructor = Array = 인스턴스.constructor = 인스턴스.[[prototype]].construtor

 

이 되는 것입니다.

 

❗ 몰론 앞에서 설명했다시피 인스턴스.[[prototype]].construtor 은 정보만 읽을 수 있는거라서 Array.prototype.constructor를 인스턴스.[[prototype]].construtor 로 접근할 수 있는 것이 아닙니다.

단지 내부적으로 이들이 모두 같다는 것입니다.

 


📖 prototype 내용 정리

 

그럼 다시 정리를 해보겠습니다.

 

Array 생성자를 통해 인스턴스 [1,2,3]을 만든다면

 

  prototype에는 배열과 관련된 메소드들이 들어있다고 한 것이 방금까지의 내용이었습니다.

 

그럼 배열 말고 다른 데이터 타입들도 똑같나요?

 

이번엔 문자열(string) 타입도 확인해봅시다.

문자열 자체에는 객체가 아니므로 [[prototype]] 속성도 없습니다.

 

배열 리터럴은 prototype으로 Array의 메소드들을 접근할 수 있지만 문자열 리터럴은 prototype 속성이 없다.

 

그렇지만 개발자가 문자열 리터럴(어떤 상수나 변수로 담겨 있지 않은 채)을 인스턴스인 것처럼 사용하려고 하면

 

 

자바스크립트 엔진이 임시로 문자열의 인스턴스를 만들어서 

 

 

그 메소드를 실행한 후 

그 결과를 얻음과 동시에 인스턴스를 다시 폐기하는 식입니다.

 

기본형 타입의 데이터들은 모두 이 같은 방식에 의해 생성자 함수를 사용하지 않거나 데이터 타입을 정의하지 않고도 메소드들을 호출할 수 있는 것입니다.

 

 

그럼 기본형이 아닌 참조형들은요?

 

참조형 데이터들은 처음부터 인스턴스이기 때문에 메소드를 호출한 순간에 임시로 인스턴스를 만들어 메소드의 접근하고 다시 폐기하는 복잡한 과정을 거치진 않습니다.

이미 갖고 있는 prototype에서 메소드를 갖고 오면 되니까요.

 

어쨌든 가장 중요한 건 문자열이든 함수든 배열이든 상관없이 자기 데이터 타입에 맞는 속성, 메소드를 갖고 올 때는 이러한 구조를 통해 이루어지는 것입니다.

 

데이터 자신에게는 메소드들이 없지만 생성자 함수의 prototype 속성에 있는 것을 [[prototype]] 이라는 연결통로에 의해 마치 자신의 것처럼 쓸 수 있다는 것입니다!

 

몰론 null, undefined는 이 이야기에서 제외됩니다.

 

각 생성자 함수의 prototype에는 각 데이터 타입에 맞는 전용 메소드들이 존재하는 것입니다.

 

우리는 지금까지 자바스크립트 내장되어 있는 배열메소드를 사용한 것을 더 자세하게 알기 위해 prototype을 배워본 거였습니다. prototype을 몰라도 배열의 map(),push(), length 속성을 잘 이용할 수 있지만 prototype을 알게 되면 더욱 멋진 코딩을 할 수 있습니다.

 

prototype을 잘 이용하면 아직은 자바스크립트에 있지 않은 메소드들을 자기 맘대로 구현할 수 있습니다.

 

String.prototype.replaceAt=function(index, char) {
    return this.substr(0, index) + char + this.substr(index + 1, this.length);
}

 

 

 

다음 시간에는 prototype으로 자바스크립트의 메소드 상속 및 동작원리를 배워봅시다.

 

prototpe으로 배워보는 메소드 상속 및 동작 원리[클릭]