var는 let이 만들어지기 전부터 존재했던 자료형입니다. 박힌 돌이 있는데도 let이 새롭게 나온데에는 이유가 있었습니다. var는 어딘가 나사빠진 기능을 갖고있기 때문 (...)
var
- 예약어와 같은 이름으로 변수 생성 가능
- 재선언(!!) 가능(재할당이 아닙니다. 재선언 입니다)
var와 let은 스코프에 대한 기준도 다릅니다. 따라서 비동기 처리에 주의해야 해요. 이 내용은 뒤에 서술하겠습니다.
스코프는 단어 그대로 범위(scope)를 의미합니다. 저는 더 쉽게 변수가 살아있는 공간이라고 이해했습니다.
아래의 코드에서 출력되는 값은 무엇일까요?
arr = [1, 2, 3];
for (let i = 0; i < 3; i++) {
setTimeout(() =>{
console.log(arr[i])}, 500 * (1 + i));
}
당장 개발자 도구를 눌러서 확인해보겠습니다. 순서대로 1 - 2 - 3
이 출력됩니다. 그렇다면 let을 var로 바꾸면 어떻게 될까요?
arr = [1, 2, 3];
for (var i = 0; i < 3; i++) {
setTimeout(() =>{
console.log(arr[i])}, 500 * (1 + i));
}
콘솔에는 undefined
가 세번 출력되었습니다. 둘 다 같은 기능을 하는 자료형인데 왜 출력 결과에 차이가 있을까요?
그 이유가 스코프에 있습니다. var는 함수 스코프를 따르고 있기 때문입니다. 즉 변수가 살아있는 공간이 함수이기 때문입니다.
위의 코드에서 i는 중괄호({})로 묶인 반복문에서 벗어났을 때 생명을 잃지 않습니다. 블록 스코프가 아닌 함수 스코프를 따르기 때문입니다. 말 그대로 함수를 벗어나지 않는 한 변수는 기능을 유지합니다.
그러나 의문이 있을것입니다.
앞서 설명한 이유를 듣더라도 콘솔이 arr[i]
를 undefined
로 읽는 것은 쉽게 이해되지 않습니다. 이는 반복문 안에 들어있는 setTimeout
과 연관이 있습니다.
setTimeout 함수는 코드가 적힌 순서와 실제 실행순서가 다른 비동기 함수입니다. (자세한 이유가 궁금하다면 이 문서를 참조해주세요)
동기, 비동기 함수가 무엇일까요? 이미 앞에서 답이 나왔습니다. 웹에 대해서 살펴봅시다.
이 그림에서 client와 server는 request와 response로 상호작용하고 있습니다. 우리는 요청(request)와 응답(response)에 집중하면 됩니다.
동기는 요청이 있을 때 바로 응답하는 것을 의미합니다. 어떤 요청을 쌓아놓고 본인이 원하는대로 처리하는 것이 아닌 즉문즉답하는 것입니다.
그럼 비동기는 무엇일까요?
동기의 반대입니다. 요청이 있을 때 바로 응답하지 않아도 됩니다. 어떤 요청을 쌓아놓고 내가 원하는 때에 원하는 순서대로 처리하는 것. 그것이 비동기입니다.
앞서 드린 설명이 잘 와닿지 않아도 괜찮습니다. 비동기를 프로그래밍에 대입했을 때, 내가 작성한 코드가 순서대로 작동하지 않고 원하는 동작을 먼저 처리한 뒤에 작동하면 그것이 비동기입니다.
자바스크립트에서는 대표적으로 addEventListner함수가 있습니다. 다시 한번 코드를 봐볼까요?
arr = [1, 2, 3];
for (var i = 0; i < 3; i++) {
setTimeout(() =>{
console.log(arr[i])}, 500 * (1 + i));
}
setTimeout 함수는 비동기 함수라서 브라우저 상황에 따라 실행 순서가 뒤로 밀릴 수 있습니다. 브라우저 상황이 나빠서 setTimeout함수가 실행되기 전에 for문이 먼저 실행되었다면 어떻게 됐을까요?
for문이 모든 반복을 끝냈을 때 i
의 값은? 블록 스코프를 따르는 경우 i
는 반복이 끝난 순간 없는 변수라고 봐야합니다. 그러나 var가 함수 스코프를 따른다는 것을 아까 설명드렸죠?
for문이 모든 반복을 끝냈을 때 후위증가하므로 i
의 값은 3입니다.
이제 모든 의문이 풀렸습니다. 앞서 변수를 let이 아닌 var로 바꿨을 때 콘솔이 undefined를 나타내던 이유는 arr[i] (= arr[3])
이 없는 인덱스를 참조했기 때문입니다. 이미 모든 반복을 끝낸 i
는 3이라는 값으로 고정돼 있습니다. 따라서 undefined가 연속으로 출력된 것이죠.
var와 비동기함수를 함께 썼을 때 생길 수 있는 문제, 예약어 중복, 재선언 미방지 등 다양한 이유로 인해 이제 var보다는 let을 사용하는 것이 권장되는 것입니다.