변수 — 값에 이름을 붙여 보관한다
Article
숫자 하나를 계산했다고 하자. 그 결과를 나중에 또 쓰려면 어딘가 적어둬야 한다. 머릿속이 아니라 프로그램 안에.
값을 담아두고 이름을 붙여 다시 꺼내 쓰는 상자. 그게 변수다.
이름을 붙인다는 것
먼저 변수 없이 코드를 써본다.
console.log(1200 * 3);
console.log(1200 * 3 * 0.1);
1200이 뭔지 알 수 없고, 값이 바뀌면 두 군데를 다 고쳐야 한다. 변수를 쓰면 이렇게 된다.
const price = 1200;
const count = 3;
const total = price * count;
console.log(total);
console.log(total * 0.1);
- 3600
- 360.00000000000006
읽기 쉬워졌고, 가격이 바뀌어도 한 줄만 고치면 된다.
선언과 할당
변수를 만드는 일은 두 단계로 나뉜다.
- 01
선언 (declaration)
이름을 만든다. 아직 값은 없다.
let name; - 02
할당 (assignment)
만들어둔 이름에 값을 넣는다.
=는 "같다"가 아니라 "넣는다"는 뜻이다.name = "준호"; - 03
한 번에 하기
보통은 선언과 할당을 붙여서 쓴다.
let name = "준호";
= 기호를 수학에서처럼 "같다"로 읽으면 곧 혼란에 빠진다. 아래 코드를 보자.
let count = 1;
count = count + 1;
console.log(count);
- 2
수학이라면 count = count + 1은 말이 안 된다. 하지만 자바스크립트에서 이 줄은 **"오른쪽을 계산해서 왼쪽에 넣어라"**는 명령이다. 오른쪽 count + 1이 먼저 2가 되고, 그 2가 count에 들어간다.
메모리 상태로 보면 이렇다.
이름표가 붙은 상자에 값이 들어 있다
- price
- 1200
- count
- 2
- name
- "준호"
이름 짓는 규칙
변수 이름은 아무렇게나 지을 수 없다. 지켜야 하는 규칙과, 지키면 좋은 관습이 있다.
| 예시 | 가능 여부 | 이유 |
|---|---|---|
| userName | 가능 | 권장되는 형태 |
| user_name | 가능 | 동작하지만 자바스크립트에서는 덜 쓴다 |
| _count | 가능 | 밑줄과 $ 로 시작할 수 있다 |
| 1stPlace | 불가능 | 숫자로 시작할 수 없다 |
| user name | 불가능 | 공백을 넣을 수 없다 |
| let | 불가능 | 예약어는 쓸 수 없다 |
관습적으로 자바스크립트는 카멜 케이스를 쓴다. 첫 단어는 소문자로, 이어지는 단어의 첫 글자는 대문자로 붙인다. userName, totalPrice, isLoggedIn 같은 식이다.
그리고 대소문자를 구분한다. name과 Name은 완전히 다른 변수다.
let, const, var
변수를 만드는 키워드가 세 개다. 왜 셋이나 되는지부터 알아야 한다.
원래는 var 하나뿐이었다. 그런데 문제가 많아서, 2015년에 나온 ES6에서 let과 const가 추가됐다. 지금은 var를 쓸 이유가 거의 없다.
const
기본으로 쓴다
- 재할당 불가
- 재선언 불가
- 블록 스코프
- 선언과 동시에 값을 넣어야 한다
let
값이 바뀔 때만
- 재할당 가능
- 재선언 불가
- 블록 스코프
- 값 없이 선언할 수 있다
var
쓰지 않는다
- 재할당 가능
- 재선언 가능 — 사고의 원인
- 함수 스코프 — 예상을 벗어난다
- 옛날 코드에서만 만난다
재할당
let은 값을 다시 넣을 수 있고, const는 없다.
let score = 10;
score = 20;
console.log(score);
const limit = 100;
limit = 200;
- 20
- TypeError: Assignment to constant variable.
const는 "상수(constant)"의 줄임말이다. 한 번 정하면 바꾸지 않겠다는 선언이다.
재선언
같은 이름으로 변수를 또 만드는 것이다. var만 이걸 허용한다.
var user = "민수";
var user = "지영";
console.log(user);
- 지영
아무 경고 없이 덮어써진다. 코드가 길어지면 어딘가에서 같은 이름을 또 선언했는지 알아채기 어렵고, 값이 조용히 바뀐다.
let으로 같은 걸 하면 즉시 막아준다.
let user = "민수";
let user = "지영";
- SyntaxError: Identifier 'user' has already been declared
에러가 나는 쪽이 더 좋은 동작이다. 실수를 실행 전에 잡아준다.
스코프
세 번째 차이는 변수가 살아 있는 범위다. 중괄호 { } 안에서 선언한 변수가 바깥에서도 보이는지의 문제다.
if (true) {
var a = "var 로 선언";
let b = "let 으로 선언";
}
console.log(a);
console.log(b);
- var 로 선언
- ReferenceError: b is not defined
var는 중괄호를 무시하고 바깥으로 새어나온다. let과 const는 중괄호 안에 갇힌다. 후자가 훨씬 예측하기 쉽다.
그래서 뭘 써야 하나
규칙은 단순하다.
- 일단 const대부분 여기서 끝난다
- 값을 바꿔야 하면 let반복문 카운터 등
- var 는 안 쓴다옛날 코드에서 읽을 줄만 알면 된다
기본을 const로 두면 좋은 점이 있다. 이 값은 안 바뀐다는 사실이 코드에 드러난다. 나중에 코드를 읽는 사람이 그 변수를 추적하지 않아도 된다.
const 는 값을 얼려버리는 게 아니다
마지막으로 가장 많이 오해하는 부분이다.
배열이나 객체를 const로 선언하면 이런 일이 벌어진다.
const numbers = [1, 2, 3];
numbers.push(4);
console.log(numbers);
numbers = [9, 9];
- [1, 2, 3, 4]
- TypeError: Assignment to constant variable.
배열에 값을 추가하는 건 된다. 하지만 numbers에 아예 새 배열을 넣는 건 막힌다.
이유는 const가 지키는 게 상자에 든 값이 아니라 상자와 이름의 연결이기 때문이다. 배열은 상자에 직접 들어 있지 않고, 상자에는 "배열이 있는 위치"만 적혀 있다.
위치를 적어둔 상자는 잠겼지만, 그 위치에 있는 배열은 열려 있다
- limit
- 100
- numbers
- 0x1a2b
- [1, 2, 3, 4]
지금은 완전히 이해하지 못해도 괜찮다. 4강 자료형에서 원시 타입과 참조 타입을 구분하고 나면 이 그림이 저절로 풀린다.
정리하면
- 변수는 값에 이름을 붙여 보관하는 상자다.
=는 "같다"가 아니라 "오른쪽 값을 왼쪽에 넣어라"다.const를 기본으로 쓰고, 재할당이 필요할 때만let을 쓴다.var는 쓰지 않는다.const는 재할당을 막을 뿐, 배열이나 객체의 내용까지 얼리지는 않는다.
다음 강의에서는 상자에 담기는 값의 종류를 본다. 숫자, 글자, 참/거짓 그리고 헷갈리기로 유명한 null과 undefined까지.