본문 바로가기
개발자도구

[[Prototype]]: Object = Object.Prototype.toString.call(obj) = [object Object]

by 로맨틱스터디 2025. 11. 16.
728x90
반응형

[[Prototype]]는 자바스크립트 객체상속받는 부모 객체(프로토타입) 을 가리키는 내부 슬롯(internal slot)이야.

쉽게 말하면:

“이 객체가 어디에서 속성/메서드를 상속받는가?
를 나타내는 숨겨진 연결 고리(link).

 

아주 중요한 개념이라 정확하게 설명해줄게.


✅ 1. 객체에는 보이지 않는 내부 슬롯이 있음

JS 객체에는 다음처럼 키-값 쌍 외에도
엔진 내부에서 관리하는 숨겨진 슬롯이 존재함.

그 중 하나가 바로 [[Prototype]].

 

예:
const obj = { a: 1 };
console.log(obj);

 

개발자 도구에서 펼쳐 보면:

a: 1
[[Prototype]]: Object

이렇게 보이지?

바로 이게 “프로토타입 체인”의 출발점.


✅ 2. [[Prototype]]은 상속용 링크

예를 들어:

const obj = {};
obj.toString();

obj에는 toString() 이 없음.
그런데 실행 가능함 → 왜?

 

obj.[[Prototype]] = Object.prototype 이기 때문.

 

그래서 JS는 다음 순서로 찾음:

  1. obj 내부에서 toString 찾기
  2. 없다 → obj.[[Prototype]] 에서 찾기
  3. 또 없다 → 그 프로토타입의 프로토타입에서 찾기
  4. 최상위까지 올라가서 없으면 에러

이 과정을 프로토타입 체인(prototype chain) 이라고 해.


✅ 3. [[Prototype]]은 JS 코드로 직접 접근 불가

이 슬롯은 언어 명세에서 내부 슬롯으로 지정된 것이라
직접 이런 식으로 접근할 수 없음:

obj.[[Prototype]] // ❌ 문법 오류

그래서 대신 써야 하는 게 다음 방법들.


✅ 4. [[Prototype]] 접근 / 설정하는 법(공식)

✔ Object.getPrototypeOf(obj)

→ 프로토타입 조회

const proto = Object.getPrototypeOf(obj);

✔ Object.setPrototypeOf(obj, proto)

→ 프로토타입 변경

Object.setPrototypeOf(obj, anotherObj);

✅ 5. __proto__ 는 [[Prototype]]의 비표준 getter/setter

개발자 도구에서는
[[Prototype]] 대신 __proto__ 로도 초기엔 표시했어.

obj.__proto__

이건 원래 비표준이었지만
너무 많이 쓰여서 현재 “웹 호환성” 때문에 유지됨.

 

그러나 본질적으로:

  • __proto__ 는 단순히
    [[Prototype]]에 접근하는 getter/setter 역할을 함
  • 실제 내부 슬롯 이름은 [[Prototype]] (중괄호 포함)

✅ 6. 모든 객체는 프로토타입을 가진다(예외: Object.create(null))

기본 객체는 이렇게 연결됨:

obj → Object.prototype → null

 

배열은:

[] → Array.prototype → Object.prototype → null

 

함수는:

function(){}Function.prototype → Object.prototype → null

 

 

728x90

Q. obj -> Obj.prototype -> null

더보기

이건 자바스크립트의 가장 핵심적인 개념이라, 완전 처음 본 사람도 이해할 수 있게 단계별로 설명해줄게.


🔥 먼저 결론 요약

 
obj → Object.prototypenull

 

이 말은:

자바스크립트의 모든 객체는 부모 객체(프로토타입)를 가지며, 이런 부모-자식 구조가 연결되어 있다. 최종 부모는 null이다.

 

이걸 프로토타입 체인이라고 한다.

 

이제 하나씩 뜯어보자.


✅ 1. Object는 “모든 객체의 근본(base) 생성자”다

브라우저 JS에서 Object 는 다음처럼 생긴 기본 생성자 함수다:

 
Object

 

즉,

const obj = {};

이렇게 객체 하나 만들면

 

JS 내부적으로는 이렇게 한 것과 동일함:

const obj = new Object();

그래서 모든 일반 객체는 Object로부터 만들어진다.


✅ 2. Object.prototype 는 “모든 객체가 상속받는 공통 부모 객체

JS는 상속을 클래스가 아니라 프로토타입 객체로 구현함.

즉, {} 로 만든 모든 객체는 다음을 공유함:

Object.prototype

 

여기에는 우리가 항상 쓸 수 있었던 이런 메서드들이 들어 있음:

  • toString()
  • hasOwnProperty()
  • valueOf()
  • isPrototypeOf()

예:

const obj = {};
obj.toString; // 있음 (하지만 obj 자체에는 없음!)

 

이 때문에 JS는 상속 관계를 이렇게 그려놓음:

obj
↓ 상속(프로토타입 링크)
Object.prototype

✅ 3. 왜 Object.prototype 의 프로토타입은 null 인가?

Object.prototype 은 프로그래밍 우주에서 가장 상위에 있는 최상위 객체임.

 

즉,

  • 더 위로 올라갈 부모가 없음
  • 그래서 프로토타입 체인의 끝이다

명세에서 이렇게 정의됨:

obj가 상속하는 부모 객체의 부모 객체는 === 없음

Object.getPrototypeOf(Object.prototype) === null     // true

그래서 프로토타입 체인은 항상 마지막에 null로 끝남.


💡 이제 전체 그림

객체 하나:

const obj = { a: 1 };

브라우저가 내부적으로 이렇게 연결함:

obj
  |
  | (프로토타입)
 ↓
Object.prototype
  |
 ↓
null

의미:

  • obj 안에서 toString() 같은 걸 찾으면 없으니
    Object.prototype 안에서 찾는다
  • Object.prototype 에도 없으면 null 이므로
    → 여기서 탐색 종료

그게 바로 “연결되었다” 라는 의미.


📌 진짜 코드로 보기

 
const obj = { a: 1 };
console.log(Object.getPrototypeOf(obj) === Object.prototype);  // true console.log(Object.getPrototypeOf(Object.prototype));  // null

🧩 비슷한 구조: 배열은?

배열도 내부적으로는 이런 구조:

[]

Array.prototype

Object.prototype

null

즉 배열도 결국 Object를 부모로 하는 구조.


🔥 초간단 요약

  • Object = 기본 객체 생성자(가장 근본)
  • Object.prototype = 모든 객체가 공통으로 상속받는 부모 객체
  • null = 부모가 없다는 의미 → 프로토타입 체인 끝
  • “연결됨” = 객체가 부모 객체로 이어져 있어 부모의 속성을 상속받는 관계

원하면:

  • 함수의 prototype 과 객체의 [[Prototype]] 차이
  • 클래스 문법이 실제로 어떻게 Object.prototype 체인으로 컴파일되는지
  • 프로토타입 체인이 실제로 동작하는 알고리즘

도 이어서 설명해줄게!


🔥 핵심 정리

  • [[Prototype]]은 JS 객체가 상속받는 부모 객체에 대한 참조
  • JS 코드에서는 직접 접근 불가 (내부 슬롯)
  • 개발자 도구에서는 보이지만, 실제 프로퍼티가 아님
  • 상속 탐색 체인(프로토타입 체인)의 핵심
  • __proto__ 는 [[Prototype]]에 접근하는 비표준 API
  • 공식 접근은 Object.getPrototypeOf(), Object.setPrototypeOf()

원하면:

  • 프로토타입 체인이 실제로 동작하는 상세 알고리즘
  • 클래스를 사용했을 때도 내부적으로 어떻게 [[Prototype]]이 구성되는지
  • 함수의 prototype 과 객체의 [[Prototype]] 차이
  • 프로토타입 오염 공격(Prototype Pollution)

까지도 설명해줄게!

 

 

Q. obj.toString

더보기

질문한 내용 정확히 짚어서 설명해줄게.


✅ 1. obj.toString 과 obj.toString() 은 완전히 다르다

✔ obj.toString

함수 자체를 가져오는 것(참조)
→ 실행 X
→ 단지 "이름이 toString인 함수가 여기 있다" 를 반환할 뿐

✔ obj.toString()

그 함수를 실행해서 반환값을 받는 것

 

즉:

 
obj.toString // 함수 참조
obj.toString() // 함수 실행

 

둘은 차원이 다르다.


✅ 2. 그럼 왜 예제로 obj.toString 을 썼냐?

예시의 목적은 “obj 객체 안에는 toString이 없지만, 프로토타입에서 상속받아서 존재한다” 를 보여주기 위한 것이라
실행이 아니라 존재 여부 확인만 한 거야.

 

예시 다시 보자:

 
const obj = {};
obj.toString;

 

여기서 의미는:

  • obj 내부에는 toString 속성이 없다
  • 하지만 obj.toString 을 찍어보면 뭔가 나온다
  • → 이는 obj가 Object.prototype에서 상속받기 때문

즉 “프로토타입 체인으로 인해 찾을 수 있다” 는 걸 보여주기 위한 예시지
"코드를 실행시켰다"는 의도가 아니었어.


✅ 3. 실행하지 않아도 함수가 보인다 → 왜냐면 JS는 "값"으로 함수도 가진다

JS에서 함수도 객체이기 때문에
그냥 “값”처럼 변수에 담거나 표시할 수 있어.

 

예:

function f() {}
console.log(f);

이렇게 해도 함수가 출력됨(실행 X).

 

obj.toString 도 같은 원리:

console.log(obj.toString);

toString 함수 객체가 출력됨
함수 본문이 보이거나 [Function: toString] 처럼 표시됨

 

하지만

console.log(obj.toString());

→ toString 함수 실행 결과(ex. "[object Object]")가 출력됨.


🔥 결론 요약

표현 의미
obj.toString toString 함수를 “가져온 것” (실행 X)
obj.toString() toString 함수를 “실행한 것”

예시에서 obj.toString 을 사용한 것은
함수 실행이 목적이 아니라
“obj가 프로토타입 체인으로부터 toString을 가지고 있다
를 설명하기 위한 것이었음.


원하면:

  • 함수도 객체라는 것의 깊은 구조
  • 함수 객체의 내부 슬롯([[Call]], prototype 등)
  • toString이 실제로 어디서 오는지(Object.prototype.toString 내부 동작)

도 설명해줄게!

Q. [object Object]좋아, 이건 자바스크립트를 처음 배우는 사람이라도 이해할 수 있게 완전 기초부터 설명해줄게.

더보기

🔥 결론부터

기본 객체({})의 toString() 결과가

 
[object Object]

이 나오는 이유:

기본 Object의 프로토타입(Object.prototype)이 정의한 “객체를 -> 문자열로 표현하는 기본 규칙” 때문이다.

 

그 규칙이 바로:

[object  타입이름 ]

 

여기서 타입이름이 Object이기 때문에

[object Object]

이 나오는 것.


✅ 1. toString() 은 Object.prototype.toString 이다

const obj = {}; 같은 기본 객체는 자신만의 toString이 없음.

따라서 프로토타입 체인에서 부모의 메서드 toString를 가져옴:

obj.toString()
Object.prototype.toString.call(obj)

즉, 진짜 실행되는 함수는 Object.prototype.toString.


✅ 2. Object.prototype.toString 의 규칙

명세(ECMAScript Spec)에 이렇게 정의됨:

객체를 -> 문자열로 변환할 때
"[object " + 내부 클래스 이름 + "]"
형식으로 반환한다.

 

여기서 내부 클래스 이름(internal class name)은
기본 객체의 경우 "Object" 이다.

 

그래서:

"[object " + "Object" + "]"

→ [object Object]


📌 그럼 내부 클래스 이름(internal [[Class]])은 뭔데?

JS 내부에는 객체에 대한 “내부 타입 태그가 존재한다.

예:

내부 class toString 결과
{} "Object" [object Object]
[] "Array" [object Array]
/abc/ "RegExp" [object RegExp]
new Date() "Date" [object Date]
null "Null" [object Null]
undefined "Undefined" [object Undefined]

 

그래서:

[].toString() → " " 로 join된 문자열이라 Array의 toString이 쓰임
Object.prototype.toString.call([]) → "[object Array]"
Object.prototype.toString.call(null) → "[object Null]"

🔥 즉 [object Object]는 그냥 "기본 객체입니다" 라는 의미

사람들이 자주 헷갈려해서 정리하면:

{} = [object Object]

= “object 타입object다”
= {} 같은 기본 객체를 문자열로 바꾼 기본 표현

 

즉 HTML이나 구조를 의미하는 게 아니라
정말로 그냥 문자열이다.


👉 직접 확인해보기

 
const obj = {};
console.log(obj.toString()); 
// → [object Object]

console.log(Object.prototype.toString.call(obj));
// → [object Object]

 

배열은?

console.log(Object.prototype.toString.call([])); // → [object Array]

 

날짜는?

console.log(Object.prototype.toString.call(new Date())); // → [object Date]

📌 왜 JSON.stringify(obj) 하면 { "a": 1 } 처럼 나오는데, toString은 이상하게 나와?

이건 목적이 다르기 때문.

함수 목적
JSON.stringify() 객체를 -> JSON 텍스트로 변환
toString() 객체의 "기본 문자열 표현" 생성(디버깅 중심)

그래서 JSON.stringify는 의미 있는 구조를 출력하지만
toString은 타입 정보만 제공한다.


🔥 최종 정리

  • {} 의 toString() 은 Object.prototype.toString 호출
  • 이 함수는 내부적으로 "Object" 라는 타입 태그를 읽음
  • 반환 포맷이 [object 타입이름]
  • 그래서 결과는 [object Object]

즉, JS의 기본 객체를 문자열로 바꿨을 때의 표준 문자열 표현일 뿐이다.


원하면:

  • 왜 Array의 기본 toString은 문자열 join인지
  • 왜 Date의 toString은 사람이 읽을 수 있는 날짜인지
  • Object.prototype.toString의 명세(구체적 알고리즘)

이런 것도 자세하게 알려줄게!

Q. Object.prototype.toString.call(obj)

더보기

좋아, 이 부분은 자바스크립트 함수 호출 방식(this 바인딩) 때문에 이해가 필요해.
차근차근 아주 쉽게 설명해줄게.


🎯 결론부터

Object.prototype.toString.call(obj)
은 toString 함수를 강제로 obj 를 this 로 해서 실행하는 문법이다.

 

즉:

toString.call(obj)
= "toString 함수야, 너의 this 를 obj 로 해서 실행해!"

그래야 Object.prototype.toString 이 obj 의 내부 타입 정보를 읽어서
[object Object], [object Array], [object Null] 같은 결과를 만들 수 있다.


✨ 1. 왜 .call(obj) 를 쓰는 거야?

자바스크립트 함수는 내부적으로 this 값을 기준으로 동작한다.

 

예를 들어:

obj.toString()

이렇게 하면
obj 가 this가 된다.

 

하지만 아래는 다름:

Object.prototype.toString()

이렇게 하면 this 가 Object.prototype 그 자체가 되어버린다.

 

→ 우리가 검사하려는 obj 의 타입을 알려주지 않음.

그래서 강제로 this 를 바꿈:

Object.prototype.toString.call(obj);

→ “이 toString 함수야, this = Object.prototype이 아니라, obj 로 해! = [object Object]


✨ 2. 왜 이렇게 해야 해?

⬅ 일반적인 toString 들은 재정의되어 있음

예를 들어 배열:

console.log([1,2,3].toString());
// "1,2,3" (배열 전용 toString)

하지만 우리는 “배열인지 아닌지"를 알아내고 싶음.

 

이럴 때 배열이 가진 toString 말고,
Object.prototype.toString(최상단 조상) 의 기능을 쓰려면:

Object.prototype.toString.call([1,2,3]); // → "[object Array]"

 

즉:

  • 배열의 toString 이 아니라
  • Object.prototype.toString강제로 “배열에 적용”하는 방식.

✨ 3. call() 은 어디에 쓰는 문법?

자바스크립트 모든 함수에는

  • call(thisArg, ...args)
  • apply(thisArg, argsArray)
  • bind(thisArg)

같은 메서드가 존재함.

이 중 call 은 “즉시 실행 + this 지정” 용도.

 

예:

function say() {
  console.log(this.name);
}

const obj = { name: "홍길동" };

say.call(obj);
// "홍길동"

obj.say();

say() 를 obj 에 붙인 적 없는데도
this 를 obj 로 잡아서 실행됨.


✨ 4. 다시 정리하면…

obj.toString()

obj 가 가진 toString 을 실행
(this = obj)

Object.prototype.toString.call(obj)

"Object 최상위 객체가 가진 toString 를 obj 에 적용해서 실행"
(this = obj)

= obj 내부 타입을 정확하게 추출하는 방법


🎉 최종 정리

표현 의미
obj.toString() obj 고유의 toString 호출
Object.prototype.toString.call(obj) Object의 기본 toString을 obj 를 this로 삼아 실행 → 내부 타입 검사할 때 사용

 

그래서 이걸 사용하면

Object.prototype.toString.call([]) → "[object Array]"                          // [].Object.prototype.toString
Object.prototype.toString.call(null) → "[object Null]"                         // null.Object.prototype.toString
Object.prototype.toString.call(undefined) → "[object Undefined]"   // undefined.Object.prototype.toString

처럼 어떤 값이든 정확한 타입 문자열을 얻을 수 있다.


원하면:

  • call/apply/bind 차이점
  • 왜 null 과 undefined 도 타입 표시가 되는지
  • [[Class]] 내부 태그의 원리

이런 것도 더 깊게 설명해줄게!

Q. [[Prototype]]: Object

더보기

좋아, 이 부분은 **“객체의 타입(type)”**과 **“객체의 부모 프로토타입([[Prototype]])”**이 섞여서 헷갈리는 상황이야.
지금 헷갈리는 지점들을 하나하나 정확하게 분리해서 설명해줄게.


🎯 최종 핵심 결론 5줄 요약

  1. obj의 타입(type) 은 "object" 이고
  2. obj가 상속받는 부모 객체([[Prototype]]) 는 Object.prototype 이다.
  3. 개발자도구는 Object.prototype 을 축약해서 “Object” 로 보여준다.
  4. 일반 객체 리터럴 {}는 내부적으로 Object.prototype 을 부모로 가진다.
  5. 타입프로토타입은 완전히 다른 개념이다.

이제 하나씩 상세히 설명해줄게.


1️⃣ obj 의 “타입(Type)” 은 무엇인가?

JS의 typeof 연산자를 보자:

const obj = { a: 1 };
typeof obj;                   // "object"

obj 의 타입은 항상 “object” 이다.
이건 단순 문자열이야. 내부 동작과는 전혀 무관.


2️⃣ 그럼 “[prototype] 은 뭐야?”

자바스크립트 객체는 상속 구조(프로토타입 체인) 를 가진다.

const obj = { a: 1 } 를 만들면 실제 내부는:

obj
   a: 1
      [[Prototype]] → Object.prototype

즉, obj 는 부모로 Object.prototype 을 갖는다.

 

프로토타입이란:

  • 상속받는 부모 객체
  • 메서드(toString, valueOf 등)들이 들어있는 곳
  • obj.toString() 을 하면 obj 에 없으므로 Object.prototype.toString 을 가져와 실행한다

3️⃣ 그런데 왜 개발자 도구는 "Object" 라고 표시함?

DevTools 는 실제 내부 값인 Object.prototype
쉬운 이름으로 보여주기 위해 “Object” 라고 표시하는 것.

 

즉:

  • JS 엔진 내부 객체 이름: Object.prototype
  • 브라우저 DevTools에서 표시하는 이름: Object

왜냐하면:

  • Object.prototype 전체를 표시하면 너무 길고 개발자를 헷갈리게 할 수 있음
  • "이 프로토타입Object 라는 빌트인 객체에서 왔어요" 라고 의미를 전달하는 축약 표현

브라우저마다 약간 다르게 표현하지만
전부 “Object” 라는 라벨로 표시하는 편이 더 일반적.


4️⃣ “왜 obj 의 타입을 개발자 도구에서 표시 안 해?”

타입은 매우 단순한 정보이고,

  • typeof obj
  • 내부 [[Type]] = Object (ECMAScript 내부)

이런 정보는 개발자 도구 객체 펼침 UI에서는 잘 안 보여준다.

 

왜냐하면:

  • 타입은 코드에서 typeof 로 확인하면 됨
  • 프로토타입은 개발자가 실수하거나 구조를 확인해야 할 때 더 중요한 디버깅 정보라서 DevTools에서 강조해서 보여줌

즉, DevTools 의 목적이 타입을 보여주는 것이 아니라
상속 관계(prototype chain)를 시각적으로 보여주는 것.


5️⃣ “왜 부모 객체를 Object라고 표시하고, Object.prototype 이라고 안 해?”

정확히 말하면:

  • 실제 부모 객체는 Object.prototype
  • DevTools 는 “이 프로토타입은 Object 라는 빌트인 객체prototype입니다” 의 의미로
    “Object” 라고 라벨만 붙여서 보여줌

즉, 진짜 값은 Object.prototype 이고
DevTools 의 UI 표현은 “Object”.


6️⃣ 일반 객체(obj)의 타입과 부모 객체 관계 다시 정리

개념값
typeof obj "object"
obj 의 [[Prototype]] Object.prototype
개발자 도구 표시 [[Prototype]]: Object
부모 객체의 실제 이름 Object.prototype

❗ “일반 객체 obj 는 Object 로부터 만들어졌잖아. 그럼 이미 부모 아닌가?”

여기서 중요한 구분:

Object (함수)

JS 기본 빌트인 생성자 함수

function Object() {}

Object.prototype (부모 객체)

Object 로 만든 인스턴스들이 상속받는 실제 부모 객체

✔ obj = {} (자식 객체)

Object.prototype 을 부모로 갖는 일반 객체

 

즉:

Object (함수)
  └── Object.prototype (부모 객체)
         └── obj = {} (인스턴스)

 

그래서 상속 구조는:

obj < Object.prototype < null

🔥 비유로 이해하면 쉽다

  • Object 함수 = "사람을 찍어내는 공장"
  • Object.prototype = "사람들이 공통으로 가진 유전자(부모 DNA)"
  • obj = {} = 공장에서 만들어진 사람

그래서 DevTools 는 사람(obj)을 클릭하면
"이 사람의 부모 DNA는 Object야" 라고 표시하는 느낌.


📌 마지막으로 직관적으로 정리

obj 의 타입

  • "object"
  • 코드에서 typeof 로 확인하는 정보

obj 의 프로토타입([[Prototype]])

  • Object.prototype (부모 객체)
  • obj상속하는 메서드들이 들어있는 곳
  • 개발자 도구는 라벨을 “Object” 로 표시할 뿐

원하면:

  • 왜 Function.prototype 도 객체인지
  • 프로토타입 체인이 실제로 메서드를 찾는 알고리즘
  • ES6 클래스와 프로토타입의 관계

이런 것도 더 깊게 설명해줄 수 있어!

728x90
반응형