웹 개발은 웹에서 동작하는 어플리케이션을 만드는 일이고, 이 어플리케이션의 정수는 데이터의 입력(input)과 출력(output)이라 할 수 있다. 변수는 이 데이터를 다루기 위한 방법이다.
컴퓨터는 메모리에 데이터를 저장한다. 메모리는 데이터를 저장하는 메모리 셀의 집합체이며, 각 셀은 고유의 메모리 주소를 가진다.
다음을 생각해보자.
18 * 2
위의 경우 18과 2라는 데이터는 임의의 메모리 주소에 저장되고, CPU는 이 값을 읽고나서 연산을 수행한다. 위의 결과, 즉, 36 또한 임의의 메모리 주소에 저장된다. 이 때, 작은 문제가 생긴다. 바로 그 데이터를 재사용할 수 없다는 것이다. 우리가 18*2를 계산했다는 것은 이를 어디에 사용할 목적이 있었음을 말한다. 연산 결과인 36을 다시 사용하려면 36이 저장된 메모리 주소에 직접 접근해야 하지만, 오류가 생길 가능성을 미연에 방지하기 위해 자바스크립트 엔진에서는 사용자가 메모리를 직접 건드리는 것을 허가하지 않는다.
이렇듯 저장된 데이터를 다시 사용하기 위한 방법이 변수이다.
변수는 하나의 값을 저장하기 위한 메모리 공간 또는 그 공간에 붙인 이름이다.
간단히 말해서, 변수란 데이터가 저장된 메모리 주소의 이름을 말한다(우리가 주소를 말할 때 좌표를 부르는 것이 아니라 '서울시 송파구 잠실동' 이라고 말하는 것처럼.). 따라서 우리가 변수를 호출하면 이는 곧 메모리의 주소로 치환되어 사용된다.
위의 코드를 다시 작성해보면
let result = 18 * 2 ;
18 * 2 라는 연산은 36 이라는 값을 생성하고, 36이라는 값은 임의의 메모리 셀에 저장된다. 이 때, 이 36이라는 값을 다시 사용하기 위해 메모리 셀의 주소에 붙인 이름이 result인 것이다. 이 이름을 '변수명' 이라고 하며, 이 변수(그러니까 메모리 주소)에 저장된 값을 '변수값' 이라고 한다. 값을 저장하는 것을 할당(assginment)라고 하며 할당된 값을 사용하는 것을 참조(referenced)라고 한다.
변수명은 사람이 임의로 붙인 이름이다. 따라서 변수명을 통해 변수값의 의미를 알 수 있다. 때문에 변수명을 지을 때는 이를 통해 값을 유추할 수 있도록 지어야 한다.
변수 선언(declaration)이란 변수를 만드는 것을 의미한다. 변수를 만들기 위해서는 반드시 선언을 먼저 해야한다. 선언을 하기 위해서는 var, let, const라는 키워드를 사용한다(다만, var의 경우 여러 문제점이 있기 때문에 이를 보안하기 위해서 let과 const가 도입되었다.).
var result;
위의 코드는 변수를 선언하는 코드이다. result라는 변수 이름을 등록하고, 값이 저장될 메모리 셀을 확보한다. 변수의 선언은 다음의 단계들을 거쳐서 수행된다.
초기화란 변수가 선언된 후 메모리 공간에 최초로 값을 할당하는 것을 말한다. var로 선언된 변수는 undefined로 초기화가 암묵적으로 자동으로 수행된다.
console.log(test);
var test ;
위의 코드를 보자. 자바스크립트 코드는 인터프리터에 의해 한줄 한줄 순서대로 실행되고 console.log가 변수 선언보다 앞에 있기 때문에 console.log(test)에는 레퍼런스 에러가 떠야 할 것 같지만 undefined를 반환한다. 그 이유는 변수의 선언이 런타임(소스코드가 한 줄씩 실행되는 시점) 이전에 먼저 실행되기 때문이다.
자바스크립트의 엔진은 런타임에 앞서 소스코드를 평가하는 과정을 거치며 런타임을 준비한다. 이때, 모든 선언문을 소스코드에서 찾아 먼저 실행한다. 이후 평가가 끝나면 선언문을 제외한 코드들을 한 줄씩 실행한다.
위의 코드를 다시보면 평가 과정에서 test가 먼저 변수로 선언되었기에 console.log(test)는 undefined를 반환하는 것이다. 다만 이는 var 키워드가 선언과 초기화가 동시에 이루어지는 특성에서 기인한다. 다음과 같은 경우를 보자
console.log(test);
let test;
위의 경우 레퍼런스 에러가 뜬다. 왜 var는 undefined이고 let은 레퍼런스에러가 발생할까? 그 이유는 var는 변수의 선언과 초기화가 동시에 진행되고, let의 경우 선언은 런타임 이전에 실행되지만, 초기화는 런타임 중 선언문에 이르러서야 실행되기 때문이다.
이처럼 변수의 선언이 마치 소스 코드의 맨 위에 있는 것처럼 동작하는 자바스크립트의 고유 특징을 변수 호이스팅 이라고 한다.(다만 이는 변수에 국한되지 않고 var let const function 등 의 키워드를 사용하는 모든 식별자 또한 포함된다. 모든 선언문은 런타임 이전 평가과정에서 실행되기 때문이다.)
값을 할당할 때는 할당 연산자(=)를 사용한다. 우변의 값을 좌변의 변수에 할당한다.
let test;
test = 123 // 'test는 123이다'가 아닌 'test에 123이 할당되었다.' 혹은 '123이 test에 할당되었다.'라고 생각하는 편이 편한다.
let test=123; //선언과 할당을 축약해 표현할 수 있다.
다만 항상 염두해두어야 할 점은, 변수의 선언은 런타임 이전 평가과정에서 실행된다는 점이다. 변수의 선언과 할당을 축약해 표현하더라도 엔진에서는 선언과 할당을 나누어서 실행한다.
console.log(test) ; // undefined
var test = 1;
console.log(test) ; // 1
이미 값이 할단된 변수에 새로운 값을 다시 할당하는 것을 재할당이라고 한다.
var test = 80;
test = 90;
(사실 var의 경우는 선언과 동시에 초기화로 값에 undefined가 할당되어 있기에 최초로 할당하는 것 또한 재할당이라고 할 수 있다.)
변수.변하는 값. 값을 재할당할 수 있기 때문에 변수라고 하는 것이다. 만약 값을 재할당 할 수 없다면 이는 상수라고 부른다. 상수는 딱 한번만 할당할 수 있는 변수인 것이다(const).
변수를 재할당하면 값이 변경된다. 여기서 주의할 점은, 처음으로 80이 할당되었던 메모리 셀의 공간을 비우고 거기에 90을 저장하는 것이 아니라, 새로운 메모리 셀을 확보하고 그 메모리 공간에 90을 할당하는 것이다. 이 때, undefined와 80은 기존 공간에 그대로 남아있게 되는데, 이를 쓰레기 값(garbage value)이라 부르며, 가비지 콜렉터에 의해 메모리에서 해제된다.
네이밍 규칙은 다음과 같다.
var test; // 가능
var $test; // 가능
var _test; // 가능
var -test; // 불가능
var 한글이름; // 가능. 하지만 권장하지 않음
또한 네이밍 컨벤션은 식별자의 가독성을 높이기 위해 규정한 규칙이다. 다음의 컨벤션이 자주 사용된다.
//카멜 케이스
var firstTest;
//스네이크 케이스
var first_test;
//파스칼 케이스
var FirstTest;
일반적으로는 변수와 함수 이름에는 카멜 케이스를 사용하고, 생성자 함수, 클래스에는 파스칼 케이스를 사용한다. 코드 전체의 가독성을 위해서는 카멜 케이스와 파스칼 케이스를 사용하는 것이 좋다.