Skip to main content Link Menu Expand (external link) Document Search Copy Copied

변수와 식별자

변수는 변할 수 있는 데이터를 의미하며 데이터가 담길 수 있는 공간 또는 그릇을 뜻합니다.

식별자는 어떤 데이터를 식별하는 데 사용하는 이름, 즉 변수명입니다.

즉, 변수는 어떤 값을 저장하기 위한 이름(식별자)을 가진 데이터를 담을 수 있는 공간을 뜻합니다.

변수를 선언한다는 것은? 변수를 사용하기 전에 변수를 사용하겠다고 컴퓨터에게 알리는 것입니다. js에서는 var, let, const키워드를 사용하여 변수 선언을 하고 할당 연산자를 사용해 값을 할당합니다. 그리고 식별자인 변수명을 사용해 변수에 저장된 값을 참조합니다.

식별자는 데이터가 저장된 메모리 상의 주소를 기억합니다. 따라서 식별자를 통해 메모리에 저장된 값을 참조할 수 있습니다.

식별자 네이밍 규칙

  • 식별자는 특수문자를 제외한 문자, 숫자, 언더스코어(_), 달러 기호($)를 포함할 수 있습니다.
  • 식별자는 특수문자를 제외한 문자,언더스코어,달러 기호로 시작해야한다. 숫자로 시작하는것은 허용하지 않습니다.
  • 예약어(await ,break ,class ,false ,for ,if ,this 등)는 식별자로 사용할 수 없습니다.

권장하지 않는 식별자 네이밍

  • 변수는 쉼표로 구분해 하나의 문에서 여러개를 한번에 선언이 가능합니다. 하지만 가독성이 떨어지기 때문에 권장하지는 않습니다.
  • 알파벳 외의 유니코드 문자(한국어, 일본어 등)로 식별자를 사용하는 것
  • 변수 이름은 변수의 존재 목적을 쉽게 이해할 수 있도록 의미를 명확히 표현해야 합니다. 좋은 변수 이름은 코드의 가독성과 생산성을 높입니다.

네이밍 컨벤션

네이밍 컨벤션은 하나 이상의 영어 단어로 구성된 식별자를 만들 때 가독성 좋게 단어를 한눈에 구분하기 위해 규정한 명명 규칙입니다. 네이밍 컨벤션을 잘 지키면 읽기 좋은 이름을 만들 수 있습니다.

  1. camelCase : 변수, 함수 ex) pageName, getCombination
  2. PascalCase: 생성자 함수(react의 컴포넌트 등), 클래스 ex) CourseMember
  3. snake_case : 상수 ex) SYMBOLIC_NAME
  4. kebab-case : 추천X
  5. typeHungarianCase : 추천X, 이름 앞에 변수의 타입을 접두어로 넣어주는 컨벤션, ch-char, db-double, str-string 등 사용

var 키워드

var name = "Kim"과 같이 변수를 선언합니다. 만약 변수에 값을 할당하지 않는다면 변수는 undefined로 초기값을 가지며 선언하지 않은 변수에 접근하면 ReferenceError가 발생합니다.

중복 선언

var키워드로 선언한 변수는 중복 선언이 가능합니다. 다시 말해 변수명이 같은 변수를 중복해 선언해도 에러가 발생하지 않습니다. 때문에 변수명이 동일하면 하나의 변수로 사용하며 로컬 및 글로벌 변수로 사용 가능합니다.

var x = 1;
console.log(x); // 1

// 변수의 중복 선언
var x = 100;
console.log(x); // 100

여기서 x는 중복 선언되었습니다. 이처럼 var를 이용해 변수를 중복 선언하면 에러없이 이전 변수의 값을 덮어씁니다. 만약 동일한 변수명이 선언되어 있는 것을 모르고 변수를 중복 선언했다면 의도치 않게 변수의 값을 변경하는 부작용을 발생시킵니다. 따라서 변수의 중복 선언은 문법적으로 허용되지만 사용하지 않는 것이 좋습니다.

변수 선언 순서 상관X

var키워드는 변수 선언 순서는 상관하지 않습니다.

var a;
console.log('a 값은' + a);

console.log('b 값은' + b);
var b;

위와 같이 변수선언을 뒤에서 해도 문제가 없습니다. 다른 언어들과 다르게 조금 특이한 케이스입니다.

호이스팅

호이스팅이란 var 선언문이나 function 선언문 등 모든 선언문이 해당 Scope의 선두로 옮겨진 것처럼 동작하는 특성입니다. 즉, js는 모든 선언문(var, let, const, function, function*, class)이 선언되기 이전에 참조 가능합니다.

console.log(foo); // ① undefined
var foo = 123;
console.log(foo); // ② 123
{
  var foo = 456;
}
console.log(foo); // ③ 456

var 키워드로 선언된 변수는 선언 단계와 초기화 단계가 한번에 이루어집니다. 즉, 스코프에 변수가 등록되고 변수는 메모리에 공간을 확보한 후 undefined로 초기화됩니다. 따라서 변수 선언문 이전에 변수에 접근하여도 Variable Object에 변수가 존재하기 때문에 에러가 발생하지 않습니다. 다만 undefined를 반환합니다. 이러한 현상을 변수 호이스팅(Variable Hoisting)이라합니다.

함수 레벨 스코프, 블록 레벨 스코프

var 키워드는 함수 레벨 스코프를 가집니다. let, const를 사용하면 블록 레벨 스코프를 사용할 수 있습니다.

함수 레벨 스코프

함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 외부에서는 참조할 수 없습니다. 즉, 함수 내부에서 선언한 변수는 지역 변수이며 함수 외부에서 선언한 변수는 모두 전역 변수입니다.

블록 레벨 스코프

코드 블록 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조할 수 없습니다.

var의 문제점

  1. 함수 레벨 스코프
    • 전역 변수를 남발할 수 있습니다.
    • for loop 초기화식에서 사용한 변수를 for loop 외부 또는 전역에서 참조할 수 있습니다.
  2. var 키워드 생략 허용
    • 의도하지 않은 변수를 전역화할 수 있습니다.
  3. 중복 선언 허용
    • 의도하지 않는 변수값 변경
  4. 변수 호이스팅
    • 변수를 선언하기 전에 참조가 가능합니다.

var와 다른 let키워드

1. 블록 레벨 스코프

let은 블록 레벨 스코프를 따릅니다.

let foo = 123; // 전역 변수

{
  let foo = 456; // 지역 변수
  let bar = 456; // 지역 변수
}

console.log(foo); // 123
console.log(bar); // ReferenceError: bar is not defined

2. 변수 중복 선언 금지

let 키워드로는 동일한 이름을 갖는 변수를 중복해서 선언할 수 없습니다. 변수를 중복 선언하면 문법 에러가 발생합니다.

3. 호이스팅

var 키워드로 선언된 변수와는 달리 let 키워드로 선언된 변수를 선언문 이전에 참조하면 참조 에러(ReferenceError)가 발생합니다. 그 이유는 let 키워드로 선언된 변수는 스코프의 시작에서 변수의 선언까지 일시적 사각지대(Temporal Dead Zone; TDZ)에 빠지기 때문입니다.

console.log(foo); // undefined
var foo;

console.log(bar); // Error: Uncaught ReferenceError: bar is not defined
let bar;

let 키워드로 선언된 변수는 선언 단계와 초기화 단계가 분리되어 진행됩니다. 즉, 스코프에 변수를 등록(선언단계)하지만 초기화 단계는 변수 선언문에 도달했을 때 이루어집니다. 초기화 이전에 변수에 접근하려고 하면 참조 에러(ReferenceError)가 발생한다. 이는 변수가 아직 초기화되지 않았기 때문입니다. 다시 말하면 변수를 위한 메모리 공간이 아직 확보되지 않았기 때문입니다. 따라서 스코프의 시작 지점부터 초기화 시작 지점까지는 변수를 참조할 수 없습니다. 스코프의 시작 지점부터 초기화 시작 지점까지의 구간을 ‘일시적 사각지대(Temporal Dead Zone; TDZ)’라고 부릅니다.

// 스코프의 선두에서 선언 단계가 실행된다.
// 아직 변수가 초기화(메모리 공간 확보와 undefined로 초기화)되지 않았다.
// 따라서 변수 선언문 이전에 변수를 참조할 수 없다.
console.log(foo); // ReferenceError: foo is not defined

let foo; // 변수 선언문에서 초기화 단계가 실행된다.
console.log(foo); // undefined

foo = 1; // 할당문에서 할당 단계가 실행된다.
console.log(foo); // 1

결국은 호이스팅이 발생하지 않는 것과 차이가 없어 보입니다. 하지만 그렇지 않습니다.

let foo = 1; // 전역 변수

{
  console.log(foo); // ReferenceError: foo is not defined
  let foo = 2; // 지역 변수
}

위 예제에서 전역 변수 foo가 출력될 것으로 보입니다. 하지만 여전히 호이스팅이 발생하기 때문에 참조 에러가 발생합니다.

블록에서 foo는 지역 변수입니다. 따라서 지역 변수 foo도 해당 스코프에서 호이스팅되고 코드 블록의 선두부터 초기화가 이루어지는 지점까지 일시적 사각지대(TDZ)에 빠집니다. 따라서 참조 에러가 발생합니다.

4. 전역 객체

전역 객체(Global Object)는 모든 객체의 유일한 최상위 객체를 의미하며 일반적으로 Browser-side에서는 window 객체, Server-side(Node.js)에서는 global 객체를 의미합니다. var 키워드로 선언된 변수를 전역 변수로 사용하면 전역 객체의 프로퍼티가 됩니다.

var foo = 123; // 전역변수

console.log(window.foo); // 123

let 키워드로 선언된 변수를 전역 변수로 사용하는 경우, let 전역 변수는 전역 객체의 프로퍼티가 아닙니다. 즉, window.foo와 같이 접근할 수 없습니다. let 전역 변수는 보이지 않는 개념적인 블록 내에 존재하게 됩니다.

let foo = 123; // 전역변수

console.log(window.foo); // undefined

const

const는 상수(변하지 않는 값)를 위해 사용한다. 하지만 반드시 상수만을 위해 사용하지는 않습니다. const의 특징은 let과 대부분 동일합니다.

1. 선언과 동시에 할당 및 재할당 금지

let은 재할당이 자유로우나 const는 재할당이 금지됩니다. 주의할 점은 const는 반드시 선언과 동시에 할당이 이루어져야 한다는 것입니다. 그렇지 않으면 다음처럼 문법 에러(SyntaxError)가 발생합니다.

2. 블록 레벨 스코프

또한, const는 let과 마찬가지로 블록 레벨 스코프를 갖습니다.

const와 객체

const는 재할당이 금지됩니다. 이는 const 변수의 타입이 객체인 경우, 객체에 대한 참조를 변경하지 못한다는 것을 의미합니다. 하지만 이때 객체의 프로퍼티는 보호되지 않습니다. 다시 말하자면 재할당은 불가능하지만 할당된 객체의 내용(프로퍼티의 추가, 삭제, 프로퍼티 값의 변경)은 변경할 수 있습니다.

const user = { name: 'Lee' };

// const 변수는 재할당이 금지된다.
// user = {}; // TypeError: Assignment to constant variable.

// 객체의 내용은 변경할 수 있다.
user.name = 'Kim';

console.log(user); // { name: 'Kim' }

객체의 내용이 변경되더라도 객체 타입 변수에 할당된 주소값은 변경되지 않습니다. 따라서 객체 타입 변수 선언에는 const를 사용하는 것이 좋습니다. 만약에 명시적으로 객체 타입 변수의 주소값을 변경(재할당)하여야 한다면 let을 사용하면 됩니다.

리터럴이란?

값을 할당할 때 사용됩니다. 문자열, 숫자형, 함수형 리터럴 등이 있습니다. 리터럴은 값을 만드는 방법, 즉 사람이 이해할 수 있는 문자 또는 사전 정의된 기호를 사용해 값을 생성하는 방법이고 문자 그대로의 값입니다. 즉, 고정된 값을 나타내는 표현 그 자체가 리터럴입니다.

let room1 = conference_room;
let current room = room1;

여기서 room1은 변수를 가리키는 식별자이고, “conference_room”는 문자열 리터럴인 동시에 room1값입니다.