for loop의 선언식에서 let과 var의 차이

조회수 482회

안녕하시렵니까. 드디어 IE를 신경 안써도 되는 사이트에 취직했습니다. 이제 let을 쓸 수 있게 된 것입니다. 촤하하

그런데 쓰다보니 이상한 현상을 발견했습니다만, 도무지 이해가 안돼 질문글 작성합니다.

질문 요약

for (let i = 0; i < n; ++i) { 
  ... 
}

for 반복문에서 선언식의 변수를 let으로 선언하면 무슨 일이 일어나나요?

알고 있는 것

  • var의 유효 범위는 함수 단위다.
  • let의 유효 범위는 블록 단위다.
  • let은 끌어올림 적용이 안된다.
  • let 변수는 시점에 따라 TDZ(Temporal Dead Zone)가 발생할 수 있다.

너의 클로저는 이미 간파했다!

function getSomeWithVar() {
  var n = 0;
  var fn = () => {
    console.log(n);
  }
  ++n;
  return fn;
}

function getSomeWithLet() {
  let n = 0;
  var fn = () => {
    console.log(n);
  }
  ++n;
  return fn;
}

getSomeWithVar()(); // 1
getSomeWithLet()(); // 1

좋아요. 이건 알겠어요.
각각의 함수가 참조하는 n은 클로저니까 둘 다 1이 맞겠죠.

않이 그런데

function getSomeWithLet() {
  var fn;
  for (let i = 0; i < 2; ++i) {
    fn = () => {
      console.log(i);
    }
  }
  return fn;
}
getSomeWithLet()(); // 1

엥? 2가 아니야? 두 번째 루프에서 증감식이 실행됐을텐데?

이미지

function getSomeWithVar() {
  var fn;
  for (var i = 0; i < 2; ++i) {
    fn = () => {
      console.log(i);
    }
  }
  return fn;
}
getSomeWithVar()(); // 2

이건 2인데?

이미지

왜죠?

왜때문에 ilet이면 증감식 실행 전의 값인걸까요?

구글은 아실지도 몰라

구글은 답을 주실지도 모릅니다. 검색해봤습니다:
https://stackoverflow.com/questions/42556873/closure-let-keyword-javascript

because you use let each anonymous function refers to a different instance of x. There is a different instance on each iteration of the loop. This happens because let has a block-level scope instead of the global function scope that var has.

예??? 각 루프가 서로 다른 인스턴스를 갖는다구요??? 그게 무슨 말이죠???

저는 그만 혼절하고 말았습니다

일단 영어를 제대로 해석했다는 가정 하에 레알참트루로 각 루프가 서로 다른 인스턴스에서 돌아간다면,

그렇다면 선언식의 let 변수는 어느 계층에 있다는 말이죠? 그리고 증감식은 도데체 어디에서 수행된다는 말입니까?

혹시 for 루프의 스코프가 있고, 그 하위에 또 다른 스코프(=인스턴스)가 생성되면서 해당 스코프에 let변수가 로컬 변수로써 따로 할당된다는 말인걸까요?

상상회로를 돌려봤습니다

혹시 이런건 아닐까요?

  1. 대전제: 유효범위 = 블록 = 스코프 = 인스턴스
  2. 함수의 유효범위 깊이는 1이라 가정.
  3. 자바스크립트의 반복문은 각 루프마다 별도의 인스턴스를 갖는다. (깊이 2)
  4. 증감식은 반복문의 매 루프가 끝날 때 수행된다.
  5. 반복문의 선언식과 증감식은 깊이 2의 인스턴스에서 수행된다.
  6. 반복문의 매 루프는 한 단계 더 들어간 인스턴스에서 수행된다. 따라서 루프끼리는 서로 영향을 줄 수 없다. (깊이 3)
  7. 선언식의 let 변수는 깊이 2의 원본을 복사해 깊이 3의 인스턴스로 전달한다. (var도 동일함)
  8. 깊이 3의 인스턴스가 종료되면 익명함수가 참조하는 i는 클로저 스코프에만 존재한다.
  9. 다음 루프가 시작되면서 깊이 2의 인스턴스의 i의 값이 증가하지만 깊이 3의 인스턴스에 있는 i는 증감식 수행 전의 값을 유지한다.
  • 외로워요 관심 좀 😂 편집요청빌런 2022.1.5 23:32
  • 아는 게 없어서 답변을 못 드리는 중입니다 ㅜㅜㅋㅋㅋ 대강 조사해본 소감으로서 아주 막연하게만 코멘트 드리자면, 기대하신 그 동작은 사실은 방지됐어야 하는 것이었고, 그래서 let 키워드가 도입되면서 방지가 잘 된 것이 아닌가 합니다. 엽토군 2022.1.8 22:18
  • 엄... 그렇군요! 편집요청빌런 2022.1.11 16:56
  • 엌ㅋㅋ 이걸 납득하시면 안됩니다 😂 어쨌든 왜 이런 것인지는 여전히 알고싶긴 하네요 엽토군 2022.1.11 17:05
  • 대충 완벽히 이해했어 짤 편집요청빌런 2022.1.11 17:52

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)