변수 선언 - var
let
키워드는 실제로 타입스크립트에서 사용할 수 있도록 하는 새로운 자바스크립트 구문이다. 자세한 내용은 다음 글에서 설명하겠지만, 자바스크립트에서 자주 발생하는 많은 문제는 let
을 사용하여 해결할 수 있음으로 가능하면 var
대신 사용해야 한다.
자바스크립트에 let
, const
이라는 새로운 타입의 두 가지 변수 선언이 추가되었다. 위에서 말했듯이, 일부는 var
와 유사하지만, 사용자가 자바스크립트에서 사용하는 일반적이면서도 중요한 오류 중 일부를 방지할 수 있다. const
는 변수에 대한 재할당을 막는다는 점에서 let
을 확장한 것이다.
타입스크립트는 자바스크립트의 상위 호환이기 때문에 let
과 const
를 지원한다. 이번 글에서는 새로운 선언에 대해 자세히 설명하고, var
보다 나은 점에 관해서 이야기한다.
자바스크립트를 제대로 알지 못하고 사용했다면 다음 섹션은 우리의 머릿속을 갱신하게 되는 좋은 방법일 수도 있다. 자바스크립트에서 var
선언의 모든 단점을 알고 있다면 건너뛰어도 좋다.
var
선언자
전통적으로 자바스크립트에서 변수는 var
키워드를 이용해서 선언했다.
var a = 10;
위 코드에서 10의 값을 가진 변수 a
를 선언했다. 또한, 아래와 같이 함수 안에서도 선언할 수 있다.
function f() {
var message = "Hello, world!";
return message;
}
그리고 함수 내의 다른 함수에서도 변수에 접근할 수 있다.
function f() {
var a = 10;
return function g() {
var b = a + 1;
return b;
}
}
var g = f();
g(); // returns '11'
위의 코드에서 함수 g
는 함수 f
에서 선언된 변수 a
를 캡처한다. 함수 g
가 호출될 때마다 변수 a
의 값은 함수 f
의 a
값을 사용한다. 그리고 함수 f
가 실행되면 함수 g
를 호출하더라도 변수 a
에 접근하고 수정할 수도 있다.
function f() {
var a = 1;
a = 2;
var b = g();
a = 3;
return b;
function g() {
return a;
}
}
f(); // returns '2'
Scope Rule
var
선언은 다른 언어에 익숙한 사람에게 이상할 수도 있는 scope rule이 있다. 다음 예제를 통해 알 수 있다.
function f(shouldInitialize: boolean) {
if (shouldInitialize) {
var x = 10;
}
return x;
}
f(true); // returns '10'
f(false); // returns 'undefined'
일부 독자는 위의 예제를 보고 놀랄 수도 있다. 변수 x
는 if
블록 내에서 선언되었지만, 블록 밖에서도 접근 가능한 것을 볼 수 있다. var
선언은 containing function
, module
, namespace
, global scope
내에서 어디서나 접근할 수 있기 때문이다. (앞에서 말한 모든 것은 나중에 다룰 것이다.) 몇몇 사람은 var-scoping
, function-scoping
이라고 부른다. 파라미터 또한 function scope다.
이런 scoping rule은 몇 가지 실수를 유발한다. 그중에서도 상황을 악화시키는 문제는 동일한 변수를 여러 번 선언해도 오류가 아니라는 것이다.
function sumMatrix(matrix: number[][]) {
var sum = 0;
for (var i = 0; i < matrix.length; i++) {
var currentRow = matrix[i];
for (var i = 0; i < currentRow.length; i++) {
sum += currentRow[i];
}
}
return sum;
}
위의 코드는 같은 변수 i
를 이중 for
문에서 참조하기 때문에 변수 i
를 덮어쓴다. 비슷한 종류의 버그가 코드 리뷰를 통과하면, 끝없는 좌절의 원인이 될 수도 있다.
Variable capturing quirks
아래의 코드 스니펫을 보고 결과를 예상해 보자.
for (var i = 0; i < 10; i++) {
setTimeout(function() { console.log(i); }, 100 * i);
}
setTimeout
은 특정 시간 후에 함수를 실행한다. (다른 것이 실행을 멈출 때까지 기다린다). 결과는 다음과 같다.
10
10
10
10
10
10
10
10
10
10
자바스크립트 개발자는 실행 결과를 예측할 수 있었겠지만, 대부분의 사람은 아래와 같은 결과를 예상했을 것이다.
0
1
2
3
4
5
6
7
8
9
setTimeout
에 전달되는 모든 함수는 동일한 scope의 같은 i
를 나타낸다. setTimeout
은 일정 시간 뒤에 호출되기 때문에 루프의 실행을 중지한 후에 실행된다. 루프의 실행이 끝날 때 i
의 값은 10이다. 따라서 함수가 호출될 때마다 10이 출력된다.
일반적인 해결 방법은 아래의 코드처럼 IIFE(Immediately Invoked Function Expression)
를 사용해서 각 반복마다 i
의 상태를 캡처하는 것이다.
for (var i = 0; i < 10; i++) {
// capture the current state of 'i'
// by invoking a function with its current value
(function(i) {
setTimeout(function() { console.log(i); }, 100 * i);
})(i);
}