1 + 1 = 2
우리는 무의식적으로 덧셈이라는 연산 기호와 피연산자 1, 결과값 2 모두 기억하고 그 의미를 알고 있기 때문에 1 더하기 1은 2야
라고 말할 수 있다.
반면, 컴퓨터에서는 연산과 기억을 따로 하는데, CPU가 연산작업을 처리하고 1과 2와 같은 값들은 메모리에 저장해서 사용한다.
메모리는 여러개의 메모리 셀 공간으로 나누어져 있는데 거기에 값들을 하나씩 저장하고 필요할때 꺼내서 사용한다. 메모리 셀에는 0x00000001
이런식으로 각각의 고유한 주소값이 있다. 주소를 잘 찾아야 원하는 값을 가져올 수 있는 것이다.
JS에서는 데이터를 저장하고 찾고할 때, 우리가 직접 주소값으로 값을 저장하고 꺼내오고 하지 않는다. 직접적으로 주소값을 건드리게 되면 예상치 못한 큰 문제가 발생할 수 있다.
대신 변수
에 원하는 값을 할당하고 참조할 수 있다!
아래 코드에서 score
변수는 100
값을 가지고 있는게 아니고, 100
값을 저장하고 있는 메모리 셀의 주소를 가리키고 있다.
var score = 100;
즉, 우리는 변수를 선언 및 할당하고 값을 참조하는데 직접적인 주소 값을 제어하는 것이 아니고 주소를 가리키는 변수를 사용하는 것이다.
변수에는 우리가 원하는 값을 할당할 수 있지만 우리는 어떤 값인지 식별하고 사용하려면 변수명을 잘 지어야 한다. 왜냐하면 그 변수가 아주 중요한 값일수도 있고, 여러번 사용할 수 있으며, 여러 사람들과 공유할 수 있기 때문이다.
예를 들어서, 수학점수를 저장하고 싶다.
만약 아래 코드처럼 score
라는 변수에 값을 할당하면 다음에 봤을때 이게 무슨 점수이지? 싶을 것이다.
score
대신에 camel case
pascal case
snake case
와 같은 변수 네이밍을 쉽게 파악할 수 있는 구조로 명확하게 적으면 좋다.
// 불분명한 변수명
var score = 90;
// camel case
var mathScore = 90;
// pascal case
var MathScore = 90;
// snake case
var math_score = 90;
변수명을 지을 때는 꼭 지켜야할 규칙 3가지가 있다.
첫번째, 특수문자를 제외한 문자, 숫자, 언더스코어(_), $ 4가지를 혼합해 만들 수 있다.
두번째, 숫자로 시작하지 말것.
세번째, 예약어를 사용하지 말것.
마지막 규칙은 예약어는 이미 JS에서 문법적으로 특정 역할을 수행하도록 정의되어 있기 때문에 사용해서는 안된다. 아래 표는 JS의 예약어이다.
출처 https://ko.w3hmong.com/js/js_reserved.htm
변수를 설명할 때, 변수명 앞에 var
라는 것을 붙이는데 이것은 변수를 만들거다라는 역할을 한다.
대표적으로 var
let
const
3가지가 있는데 원래는 var
만 있었다가 var
가 함수 레벨의 스코프만 지원해 전역적으로 변수가 사용되는 문제가 있어 ES6 이후부터 let
const
키워드가 지원되기 시작했다.
var score;
키워드 var
를 사용해 score
라는 변수를 선언했다. 이때 JS엔진은 변수를 선언함에 따라 2가지의 역할을 수행한다.
undefined
를 확보한 메모리에 저장해 초기화한다.분명 score
라는 변수에는 아무런 값도 할당하지 않은 상태이지만, 변수로 선언이 되면 JS엔진은 알아서 undefined
라는 원시 타입의 값으로 초기화해둔다. 왜냐하면 이전에 사용한 필요없는 값이 들어 있을 수 있기 때문이다. 즉, 미리 초기화함으로써 쓰레기 값 을 사용할 수 있는 위험을 피할 수 있다.
var score = 90;
위 코드는 한 줄로 score
라는 변수를 선언하면서 90
이라는 값을 할당하고 있다. 하지만 변수의 선언과 할당은 완전히 다른 시점에서 실행된다.
예를 들어, 아래 코드를 실행했을 때 참조 에러가 발생할 것이라고 예측하기 쉽다.
왜냐하면 score
라는 변수가 선언도 되기전에 console.log
를 실행하고 있고 JS는 인터프리터 언어로 한줄씩 실행 하기 때문이다.
console.log(score); // undefined
var score;
실제로는 에러가 발생하지 않고, undefined
값이 출력된다. 왜 그럴까? 🤔
위에서 언급했듯이 실행되는 시점이 다르기 때문이다.
변수의 선언은 런타임 이전에 먼저 실행된다.
JS 엔진은 소스 코드 실행을 위한 준비 단계에서 모든 선언문(변수, 함수, 클래스 등등)을 찾아 먼저 메모리에 공간을 확보해 둔다. 즉, 변수를 선언하는 코드가 소스코드 어디에 위치해 있든지 상관없이 선필선언된다는 것이다. 따라서 위의 코드는 에러 없이 undefined
를 출력한다.
즉, 변수 호이스팅은 JS 엔진에서 변수가 선언되는 시점이 런타임 시점과 다르기 때문에 발생할 수 있는 현상이다. var
let
const
키워드 뿐만 아니라 함수나 클래스 키워드처럼 선언되는 모든 식별자는 호이스팅이 된다.
그렇다면 아래 코드는 어떤 결과를 보여줄까?
console.log(score); // undefined
var score = 90;
console.log(score); // 90
score
라는 변수를 선언함과 동시에 90
이라는 값을 할당한 것처럼 보이지만, 실제로는 선언과 할당은 분리되어 실행된다.
변수 호이스팅에서 설명했듯이 런타임 이전에 score
라는 변수가 선언되고 난 후 한줄씩 코드가 실행되기 때문에 나중에서야 90
이라는 값이 할당이 된다.
따라서 undefined
와 90
이 순차적으로 출력될 것이다.