• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    미해결

prototype chaining 강의 예제로 만들어진 toString 작동원리(?) 설명 부탁드립니다

20.06.02 12:10 작성 조회수 82

1

안녕하세요! 강의 4:23부터 나오는 toString method를 제대로 이해 못한 것 같아서 질문드립니다.. 

제가 이해한 바는 다음과 같습니다:
1. obj.toString()을 호출하면(실행시키면?) res 배열이 생성

2. obj의 각 프로퍼티 값에 대해 toString() 실행.

2.1.  a: 1의 경우 1이 객체가 아니므로 기존 toString() 메서드가 실행됨. res[0] = a: 1

2.2. b: {c: 'c'}의 경우

2.2.1. 값인 {c: 'c'}가 객체이므로 {c: 'c'}에 예제에서 만든toString() 자신이 다시 호출됨. {c: 'c'} 반환.

2.2.2 res[1] = b: {c: 'c'}

3. {res[0], res[1]} 반환

 질문드리고 싶은 내용은 다음과 같습니다:

1. 제가 잘못 이해하고 있는 부분이 있는 것 같아서 어떤 부분을 잘못 이해하고 있는지 알려주시면 감사하겠습니다ㅜ

확인차

var obj = {a: 1, b: 'c', d: {c: 'c'}} ;

Object.prototype.prac = function(){

var res = [];

for(var key in this){

    res.push(`${key}: ${typeof this[key]===

                'object'? this[key].prac(): this[key].toString()} 

            `);

       };

return '{'+res.join(', ')+'}';

}

로 예제를 바꿔서 실행해봤는데 반환값이

a: 1, b: c, d: {c: 'c' 로 마지막 프로퍼티 값에 뒷쪽 중괄호가 반환이 안되어서요, 

원리를 잘못 이해하고 예제를 바꿔서 이런 오류가 나는 게 아닌가 싶은 생각이 들었습니다.. 

중괄호가 반환되지 않는 이유도 함께 설명해주시면 감사하겠습니다..!

2. 윗 obj.prac() 반환값에 prac method가 포함되었습니다. 강의 예제와는 달리 method가 함께 반환된 이유를 알고 싶습니다.

강의 잘 들으면서 도움 많이 받고 있습니다! 답변 해주시길 기다리겠습니다..! 감사합니다!

답변 1

답변을 작성해보세요.

2

설명의 편의상 2번 먼저 답을 드리겠습니다.

내장된 prototype 메서드들은 모두 enumerable하지 않도록(열거대상에서 제외되도록) 설정되어 있습니다.
toString 역시 마찬가지입니다.
따라서 obj.toString()을 해도 prototype 내부 메서드들은 출력되지 않는 것이지요.
반면 prac 메서드는 prototype에 새롭게 추가된 메서드로 enumerable 속성은 default인 true로 설정된 상태입니다.
때문에 for in문에 의해 열거대상에 포함되게 됩니다.

1번의 경우, 아마도 2번과 연관이 있는 것이 아닐까 조심스럽게 추측해 봅니다.
객체가 아닌 a, b 프로퍼티의 값들 및 d 프로퍼티 내부 객체의 c 프로퍼티의 값을  출력할 때까지는
toString 메서드를 이용하니 문제가 없었다가,

d 객체의 열거대상에 포함되는 prac 프로퍼티를 출력하기 위해서 Object.prototype.prac 메서드를 실행하니,
이제는 프로토타입 체이닝을 타고 계속해서 prac 메서드를 출력하고자 하게 됩니다.

Object.prototype.prac
Object.prototype.__proto__.prac
Object.prototype.__proto__.__proto__.prac ...

이런 식으로, 논리적으로는 Object.prototype이 모든 객체의 최종점이긴 하지만
Object.prototype 역시도 객체이기 때문에, 여기에 다시 __proto__에 접근하고자 하면
똑같은 객체임에도 불구하고 접근이 됩니다!!

따라서 "d: {c: c," 이후에는 
(d: { c: c, prac: func(), prac: func(), prac: func(),  ... ) 같은 식으로 
prac 프로퍼티의 결과값들이 무한대로 출력되거나,
혹은 중간에 Maximum call stack error를 던져야 할 것 같은데,

아마도 크롬 브라우저에서는 이러한 무한한 접근을 자동으로 중단하고 넘기는 로직이 마련되어 있는 것 같네요.
'중단'했기 때문에 이후의 결과인 '}'는 출력되지 않고,
이후 문제 없는 다음 코드를 이어서 실행하도록 한 것 같습니다.

* 테스트삼아 사파리에서 돌려보니 prac의 결과가 두 번 출력되고 정상적으로 '}'가 출력되네요.
브라우저별로 prototype에 중복 접근하려는 시도에 대한 처리방식이 다른가 봅니다.

다음과 같이 prac을 enumerable하지 않도록 설정하시면 문제 없이 잘 출력되는 걸 확인하실 수 있습니다.

var obj = {a: 1, b: 'c', d: {c: 'c'}} ;

Object.defineProperty(Object.prototype, 'prac', {
    value: function(){
      var res = [];
      for(var key in this){
         res.push(`${key}: ${typeof this[key] === 'object' ? this[key].prac(): this[key].toString()}`);
      }
      return '{'+res.join(', ')+'}';
    },
    enumerable: false
})

obj.prac();