자바스크립트는 프로토타입 기반의 언어이다.
그렇다면 프로토타입은 무엇일까?
프로토타입은 자바스크립트에서 자신을 생성한 객체의 원형을 의미한다.
모든 객체는 자신의 부모 객체와 연결되어 있고, 이 프로토타입을 이용하면 객체지향의 상속처럼 속성을 사용할 수 있게 해준다.
프로토타입은 추상적인 용어로 헷갈리는 부분이 많기 때문에 아래부터는 예시와 함께 이해하도록 한다.
[[prototype]]
& prototype property
function Student(name, age){
this.name = name
this.age = age
}
const A = new Student('Park', 20)
생성자 함수를 통해 A라는 객체를 생성했다.
A객체와 Student함수객체를 확인해보면, 두 객체는 [[prototype]]
을 갖고 있다.
하지만 prototype 이라는 프로퍼티
는 함수객체인 Student만 갖고 있는 것을 알 수 있다.
__proto__
로 접근할 수 있다. 위의 예시를 살펴보면,
Student.prototype.constructor === Student
// true
A.__proto__ === Student.prototype
// true
Student 라는 함수 객체도 [[prototype]] 이 있고, 이를 통해 상위 객체의 프로토타입을 참조하고 있는 것을 알 수 있는데, 과연 이 prototype의 끝은 어디 일까?
자바스크립트에서는 함수도 객체이다.
Function 이라는 키워드는 함수이자 객체라고 할 수 있고, 이 또한 prototype을 갖는다.
결국 Student 객체의 [[prototype]]은 Function의 prototype property를 의미한다.
Student.__proto__ === Function.prototype
// true
프로토타입 property의 루트는 Object prototype이다.
-> 자바스크립트의 모든 객체는 Object 에서 파생되고, 함수 또한 마찬가지이다.
따라서 아래와 같은 결과를 확인 할 수 있다.
/* 1 */
Student.__proto__ === Function.prototype // true
/* 2 */
Function.prototype.__proto__ === Object.prototype // true
/* 3 */
Student.prototype.__proto__ === Object.prototype // true
/* 4 */
Object.prototype.__proto__ // null
프로토타입을 통해 상위 객체의 속성과 메소드를 연결하는 것
위 개념에서 본 [[prototype]] 즉, _ _proto_ _
를 통해 최상위 Object prototype까지 접근 할 수 있다는 것을 알았고, 연결하면서 공유된 모든 속성과 메소드를 사용할 수 있는 것이 프로토타입 체인이라고 할 수 있다.
지금 까지 프로토타입이 무엇인지 몰랐어도, 사실은 자바스크립트를 사용하면서 자연스럽게 프로토타입 체인을 사용하고 있었다.
const myStr = "abc"
console.log(myStr.toUpperCase())
// "ABC"
myStr 어디를 찾아보아도 메소드를 정의하지 않았다.
myStr 이라는 스트링을 선언했을 뿐인데 만들어 놓지도 않은 toUpperCase
라는 함수를 사용할 수 있다.
당연하듯 사용해 왔지만, 사실 프로토타입 체인
을 통해 가능한 일이다.
myStr.__proto__ === String.prototype
// true
String 이라는 키워드는 함수이고 const myStr = "abc"
를 했을 때 String prototype을 연결하여 myStr 객체를 생성한다.
즉, String 은 prototype 프로퍼티
를 갖고 있고, myStr 의 [[prototype]]이 연결하고 있다.
String 안에 prototype 프로퍼티가 있고, 그곳에 여러 스트링에 사용될 메소드들이 정의되어 있다.(toUpperCase도 여기에!)
만약 현재 객체에 없는 속성을 호출하면, 프로토타입 체인을 통해 상위 객체의 프로토타입 프로퍼티를 확인하고 없으면 최상위 Object prototype의 property까지 확인한다.
Object.prototype.size = function(){
console.log(`size -> ${this.length}`)
}
length라는 속성으로 string 객체의 크기를 알 수 있지만, size라는 함수로 접근하기 위해
최상위 Object의 프로토타입 속성에 size함수를 정의하였다.
myStr.size()
// "size -> 3"
myStr 에 없음 -> String prototype에 없음 -> Object prototype
이렇게 _ _proto_ _
값을 연결하여 프로토타입 체인으로 연결된 속성들을 사용할 수 있다.
최상위 Object에도 없으면? -> 에러발생
const fruit = ["apple", "banana", "peach"]
배열에서 마지막 값을 리턴해주도록 만들고 싶다.
물론, 함수로 만들어 사용하거나 배열의 크기를 가지고 매번 값을 얻을 수 있다.
하지만 프로토타입을 이용하면 가독성 있고, 재사용성 높은 코드작성이 가능하다.
모든 Array에 적용하고 싶기 때문에
Array.prototype.getLastValue = function(){
return this[this.length-1]
}
이렇게 작성해준다.
const lastFruit = fruit.getLastValue()
console.log(lastFruit)
// "peach"
사실 지금까지 개발을 하면서 prototype을 건드려 본적은 없다..
하지만 큰 규모의 객체지향 프로그래밍에 적용한다면, 충분히 사용할 가치가 있는 개념인 것 같다.
http://insanehong.kr/post/javascript-prototype/
https://mygumi.tistory.com/312
https://medium.com/@bluesh55/javascript-prototype-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-f8e67c286b67