카테고리 없음

[TIL] 22.03.11 (004) Scope

couch 2022. 3. 11. 17:49

오늘 배운 것

 

1. var 로 정의하면 이미 생성된 상태인가?   -> Yes

강의 듣다가 도대체 왜 이게 문제 없이 실행되는지 궁금해졌다.

상위요소를 만든 뒤 하위요소를 거기에다 append하는 건 해 봤지만, 그 역순이 가능하단 말인가..?

해당 하위요소를 특정할 수 있는 선택자가 있는 것도 아닌데....?

//구구단 표 만들기
var tableEl = document.createElement("table");
for (var i = 1; i < 10; i++) {
  var trEl = document.createElement("tr");
  for (var j = 1; j < 10; j++) {
    var tdEl = document.createElement("td");
    tdEl.append(i * j);
    trEl.append(tdEl);
  }
  tableEl.append(trEl);
}
document.querySelector("body").append(tableEl);

직접 돌려봐서 가능하다는 건 알겠는데 '왜'를 모르겠어서 끙끙대다 결국 slack에 질문했다.

나는 왜 질문할 줄을 모르는가...? 강의 듣는 자의 특권인데 이용해야지 ㅎ

 

+) 답변 받고 한 번 더 질문한 뒤에야 깨달았다.

온갖 새로운 개념들을 배우며 머리가 뒤죽박죽인 상태에서 내가 변수와 함수를 헷갈렸다는 것을...

var trEl = ... 이 부분은 document.createElement로 <tr>이라는 element를 만든 다음 trEl이라는 이름에 바인딩 한 것인데, 나는 '<tr> 태그를 생성하는 함수 trEl을 정의한 것'이라고 잘못 이해한 것이다 ㅎㅎㅎㅎㅎㅎㅎㅎ

그러니까 자꾸 '아니 tr 태그를 만드는 함수가 정의만 됐을 뿐이지 아직 생성된 건 아닌데 이게 어떻게 가능해...?'하고 갸우뚱한 것..

반성의 의미로 관련 글 하나 읽음. https://curryyou.tistory.com/353

이런 바보같은 실수를 겪으면서 개념이 더 단단해지리라고 믿는다. 하하핳핳하하하하

 

 

2. JS에서 Scope의 개념

1번을 검색하다가 나오길래 이 참에 공부했다. eloquent 읽다가 제대로 이해 못했던 부분.

 

  • static scope = lexical scope = 어휘적인 유효범위 = 실행하는 위치가 아닌, 작성된 위치에 따라 결정되는 유효범위. '원래 다 그런 거 아냐..?' 했는데, JS는 기본적으로 렉시컬 스코프를 쓰고, 오래된 언어 중에는 dynamic scope를 쓰는 언어도 있다고 한다.
  • var은 함수레벨 스코프 변수를 만들고, let과 const는 블록레벨 스코프 변수를 만든다. var는 블록 레벨 스코프보다 더 많은 혼란을 야기하기 때문에 요즘 잘 쓰이지 않는다고 한다..!

 

 

3. foo와 bar는 대체 뭐란 말인가!?

온갖 설명글에서 봤지만 뭘 가리키는 건지 도통 모르고 있다가 드디어 '갑과 을', 'var=i' 정도의 관용적 이름이라는 걸 알았다.

검색하면 다 이상한 어원 얘기가 나와서 맨날 '뭔소리야' 하고 백스텝했는데 ㅎㅎㅎㅎㅎㅎㅎㅎ

별 의미 없다는 걸 알고 나니 오히려 재밌게 읽을 수 있었다.

 

회고

  • 클로저의 정의까지는 이해했다.
클로저 =
함수 + 함수를 둘러싼 환경(Lexical environment)

 이 "유명한" 반복문 예제가 의도대로 작동하지 않는 이유도 이해했다. 0.1초 뒤에 console.log(i)를 실행하면, i에 명령 당시의 바인딩이 들어가는 게 아니고 실행되는 시점의 i값을 참조하기 때문이라는 것.

function count() {
    var i;
    for (i = 1; i < 10; i += 1) {
        setTimeout(function timer() {
            console.log(i);
        }, i*100);
    }
}
count();

 근데 해결 방법으로 제시된 것이 왜 의도대로 작동하는 건지는 아직 모르겠다 @.@

 

+) okky에 질문하려다가 다른 블로그 글에서 의문을 해결했다.

 의문1) 스코프를 추가했을 때 해결되는 이유 : 

색칠해 보고서야 어렴풋이 이해함

   클로저(j) 함수가 없다면, 0에서 100까지 모든 함수가 다 예약된 뒤에 i를 바라보고 '값 줘' 하겠지만

   클로저(j) 함수가 있음으로 해서 클로저(0), 클로저(1), 클로저(2) 가 다 각자의 비빌언덕 i를 갖게 되는 것.

   그러니까, 물론 클로저(j) 안의 i값도 물론 계속 바뀌지만 클로저(j)자체가 단일한 존재가 아니라 for문 돌아갈 때마다 새로 생성되는 함수이니까 가능한 것. 어우 헷갈려.

 

 의문2) 저 실행식 대체 뭐야...?

 사실 원 설명문을 읽고 바로 이해가 안 됐던 이유가 '즉시실행함수'의 존재를 몰랐기 때문 ㅋㅋㅋㅋ

 도대체 j 자리에 i값을 넣어주는 행위가 없는데 어떻게 i를 대입한 결과가 나와......? (⊙.⊙ 동공지진)

 이러고 있었다 ㅋㅋㅋㅋ

 

의문3) 블록 스코프에 저장된 값은 안 변하고 계속 남아있는 건가...?

잘은 모르겠지만 블록스코프를 이용하면 count() 함수까지 나가서 참조하기 전에 내부의 let에서 참조할 값을 찾아 끝나겠거니(function 추가한 거랑 비슷한 효과가 있겠거니) 하고 넘어가기로 했다.. 안 익숙해서 어렵당..

 

의문4) 모든 console.log의 예약(setInterval)을 건 시점이 미세하게나마 다를 것인데 어떻게 밀리지 않고 0.1초 간격으로 출력될 수가 있지?

그렇다고 한다 ㅎ