지난 220622 TIL 에서 toString()을 활용한적이 있다. 매개변수를 주면 그에 해당하는 진수를 스트링으로 반환하는 메소드 즈음으로 알았다. 그런데! MDN에서 보면 Object.prototype.toString()으로 분류 되어있다. 여기서 Object?? Prototype??은 무엇일까. 분명 숫자 타입과 사용했던 것으로 알고 있는데 객체가 왜 등장 하는 것일까.
우선 toString 구문과 설명이다.
obj.toString()
모든 객체에는 객체가 텍스트 값으로 표시된거나 객체가 문자열이 예상되는 방식으로 참조 될 경우 자동으로 호출 되는 toString()이 있다고 한다. toString()은 Object에서 비롯된 모든 객체에 상속된다고 한다. 이 메서드가 사용자 지정 개체에서 재정의 되지 않으면 toString()은 [object type]을 반환한다고 한다.
우선 Java, C++는 클래스 기반 객체지형 프로그래밍 언어라고 한다. 이와 달리 자바스크립트는 프로토타입 기반 객체지향 프로그래밍 언어라고 한다.하지만 ECMAScript 6에서 부터 클래스가 추가 되었다고 한다.
사실 자바스크립트의 모든 객체는 부모 역할을 하는 객체와 연결되어 있다고 한다. 객체 지향에서 상속 개념과 같이 부모 객체의 프로퍼티 또는 메소드를 상속받아 사용할 수 있다고 한다. 이러한 부모 객체를 Prototype객체 또는 Prototype이라고 한다. Prototype객체는 생성자 함수에 의해 생성된 각각의 객체에 공유 프로퍼티를 제공하기 위해 사용한다고 한다.
하나의 A라는 객체가 생성되면 A라는 prototype이 생성되고 A'prototype의 생성자(constructor)는 A가 된다고 한다. 어쩌면 순환참조 하는 것이라고 말해도 될 것이다.
var Dog = {
naem : 'ddoddo'
}
console.log(Dog.hasOwnProperty('name')) //true
Dog라는 객체에는 hasOwnProperty라는 함수가 없지만 작동한다는 것이다. 결론부터 말하면 이유는 객체 Dog의 __proto__
의 생성자는 Object
이고 Object
의 prototype에 있는 함수; 프로퍼티를 사용한 것이기 때문이다.
console.log(Dog.__proto__ === Object.prototype) //true
__proto__
자바스크립트의 모든 객체에는 __proto__
(이하 [[prototype]]; '언더바언더바 proto 언더바언더바' 이다.)를 갖으며, 인터널 슬롯(internal slot)이라고 한다. 상속을 위해 사용 된다고 하며, 함수도 객체이기 때문에 [[prototype]]을 갖는다고 한다.
그런데 함수 객체는 일반 객체와 달리 prototype 프로퍼티도 소유하게 된다고 한다. 너무 말이 어려웠다. 예를 들면서 설명해 보겠다.
function Dog(name){
this.name = name
}
let dog1 = new Dog()
console.log(dog1.__proto__ === Dog.prototype) //true
console.log(Dog.prototype.__proto__ === Object.prototype ) //true
console.log(Dog.__proto__ === Function.prototype) //true
console.log(Function.prototype.__proto__ === Object.prototype) //true
Object
를 부모객체 처럼 참조하는 것으로 이해했다.생성자라고도 말하고, 프로토타입 객체는 constructor를 갖는다. 객체 입장에서는 자신을 생성한 객체를 가르킨다고 한다.(참조 사이트에서는 'constructor 프로퍼티'라고 표현하는데 정확히 이해가 가지않아 'constructor'로만 표현했다.
다른 예를 보자.
function Dog(name){
this.name = name
}
console.log(Dog.prototype.constructor === Dog) //true
console.log(dog1.constructor === Dog) //true
console.log(Dog.constructor === Function) //true
자바스크립트는 특정 객체의 프로퍼티나 메소드에 접근하려고 할 때, 해당 객체에 접근하려는 프로퍼티 또는 메소드가 없다면, [[prototype]]이 가리키는 링크를 따라 자신 부모 역할을 하는 프로토 타입 객체의 프로퍼티나 메소드를 차례대로 검색한다고 한다. 이것을 프로토타입 체인
이라고 한다.
처음에 나왔던 예시와 똑같은 예시이다.
var Dog = {
naem : 'ddoddo'
}
console.log(Dog.hasOwnProperty('name')) //true
//프로토타입 체인을 통해서 작동하는 것으로 이해하는 것이 좋겠다.
이어서 예시를 보자.
console.log(dog.__proto__ === Object.prototype) //true
console.log(Object.__proto__ === Function.prototype) //true
console.log(Function.prototype.__proto__ === Object.prototype) //true
Object의 [[prototype]] 가 Function.prototype을 참조 하고, Function.prototype은 Object.prototype을 참조한다는 것을 알 수 있다.
결론적으로 객체의 프로토타입 객체는 Object.prototype 이다. 이때 Object.prototype 객체를 프로토타입 체인의 종점(End of prototype chain)이라고 한다.
객체를 생성하는 방식에 따라 세부적으로 프로토 타입 체인이 다르니 참조 사이트에서 더 확인해 보자!
이 페이지의 발단의 결말이 여기라고 생각한다. MDN사이트에서는 Object.prototype.toString()으로 나와 있는데, 메소드 사용할 때는 객체와는 일절 상관 없었다.
자바스크립트에서 원시 타입(number, string, boolean, null, undefined - 찾아보니 BigInt, Symbol 더 있었다.)과 객체로 나뉜다고 한다.
그런데 예시를 보자.
let s = 'dog'
console.log(typeof s) //'string'
console.log(s.constructor === String) //true
let str = new String('dog')
console.log(typeof str) //'object'
console.log(str.constructor === String) //true
분명 String()으로 생성한 문자열 객체와 원시 타입 문자열과는 type이 다르다는 것을 알 수있지만 같은 생성자를 가지고 있음을 알 수 있다. 원시 타입으로 프로퍼티나 메소드를 호출할 때 원시 타입과 연관된 객체로 일시적으로 변환되어 프로토 타입 객체를 공유하게 된다고 한다.
항상 하는 얘기지만... 배운것을 글쓰는 건 어렵다! 위 내용은 toString()을 설명하기 위해 생략한 내용도 많으니 아래 사이트를 더 공부를 해야겠다.
[Object.prototype.toString(), MDN, 2022년06월24일 접속]
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/toString#%EC%8B%9C%EB%8F%84%ED%95%B4%EB%B3%B4%EA%B8%B0
[JavaScript 객체 지향 프로그래밍 - 15. prototype vs proto, 생활코딩 Youtube, 2022년06월24일 접속]
https://youtu.be/wT1Bl5uV27Y
[프로토타입, poiemaweb, 2022년06월24일 접속]
https://poiemaweb.com/js-prototype#42-%EC%83%9D%EC%84%B1%EC%9E%90-%ED%95%A8%EC%88%98%EB%A1%9C-%EC%83%9D%EC%84%B1%EB%90%9C-%EA%B0%9D%EC%B2%B4%EC%9D%98-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85-%EC%B2%B4%EC%9D%B8