작성일 : 2025.07.15-07.25
작성자 : 이참
JavaScript는 변수를 선언할 때 C, C++과 달리 타입을 선언하지 않는데, 이는 자바스크립트가 타입 추론(type inference) 기능을 가지고 있기 때문이다.
이로 인해 JavaScript는 총 3가지 변수 선언 방법(var, let, const)을 가지며, 각 선언 방법은 서로 다른 특성을 가지고 있다. 따라서 용도를 잘 고려하여 적절히 변수를 선언하자.
각 키워드의 차이를 알기 위해 scope 개념에 대해 먼저 알아보자.
scope는 쉽게 말해 영향을 미칠 수 있는 범위(접근가능한 범위) 를 뜻한다. 이후 함수를 다룰 때에도 등장할 개념이니, 지금은 간단하게만 알고 넘어가자.
JavaScript에는 크게 세 종류의 scope가 존재한다.
global scope : 전역 범위로, 스크립트 모드에서 실행되는 모든 코드의 기본 범위. global scope인 경우, 블록 안에 선언되어 있어도 블록 외부에서 사용 가능하다.
module scope : 모듈 범위로, 모듈 모드에서 실행되는 코드의 범위다.
function scope : function으로 생성된 범위이다. JS에서 함수는 범위를 생성하며, 함수 내에서만 정의된 변수는 함수 외부나 다른 함수 내에서 접근할 수 없다.
참고로 함수와 관련해서는 이후 closure등 다룰 것들이 많다. - 와! 설렌다!
또한 추가 범위로 block scope가 존재한다.
block scope : 블록 범위로, 중괄호 쌍으로 생성된 범위를 뜻한다.현재 var는 사용이 지양되는 선언 방법이지만, let과 const가 등장하기 이전에는 변수 선언의 유일한 키워드였다.
var로 선언한 변수는 재선언과 재할당이 가능하다는 특징이 있다.
또한 function scope로, 함수 밖에선 접근될 수 없고 선언된 블록 바깥에서 접근될 수 있다. 이로 인해 코드의 네임스페이스를 오염시킬 수 있고, run-time에서 의도하지 않은 논리적 오류를 발생시킬 수 있다.
{
var x = 1;
var x = 3;
}
console.log(x); // 3
ECMAScript6(ES6)부터는 변수 및 상수를 선언하기 위해 let, const 키워드가 등장했다. let으로 선언한 변수는 값을 대입하기 전까지 undefined를 가진다.
let으로 선언한 변수는 재선언은 불가능하지만, 재할당은 가능하다는 특징이 있다. 또한 block scope로, 블록 내에서 쓰인 변수를 블록 외부에서 접근하려 하면 Error가 발생한다.
{
let x = 1;
x = 3;
}
console.log(x); // Error
const는 선언과 동시에 초기화가 필요하며, 상수를 선언할 때 사용하는 키워드이다.
const로 선언한 변수는 재선언 및 재할당이 불가능하다는 특징이 있다. let과 동일한 block scope이다.
{
const MAX_WIDTH = 840;
MAX_WIDTH = 900; // Error
}
console.log(MAX_WIDTH); //Error
참고로, 상수를 선언할 때는 보통 대문자와 underscore로 작명한다. (ex : MAX_WIDTH) 자세한 내용은 인터넷에
Naming Rule을 검색하면 알 수 있으며, 기회가 되면 한 번 정리해서 업로드할 예정이다.
[주의] 함수는 함수 선언으로는 호이스팅 되지만, 함수 표현식은 호이스팅 되지 않음에 주의하자.
JavaScript는 프로그램을 실행할 때, 모든 변수 및 함수의 선언을 해당 스코프의 최상단으로 끌어올려 선언한다. 이를 Hoisting이라고 하며, 아래의 예제를 통해 자세히 알아보자.
console.log(name); // undefined
var name = "이참";
console.log(blog); // Error
let birth = "trueDOM.html"
보통 변수를 선언하기 전에 그 변수를 사용하게 되면 에러가 발생한다고 알고 있지만, JS는 hoisting으로 인해 해당 scope에 있는 모든 변수 및 함수가 스코프의 최상단에서 선언된다. 이로 인해 해당 변수를 사용하는 함수보다 변수 선언이 더 위로 올라가게 되며, 이는 최근 var의 사용이 지양되는 이유와 연결되어 있다.
let의 경우, hoisting에 의해 선언이 최상단으로 올라가게 되어도 선언과 undefined의 초기화가 동시에 이루어지지 않기 때문에 hosting이 되더라도 출력할 값이 없어 Error가 발생하게 된다.
그러나 var는 선언과 동시에 undefined로 초기화 되기 때문에, 값을 할당하기 전에 해당 변수를 써도 Error가 발생하지 않는다. 따라서 var보다는 let, const의 사용을 권장한다.
Error 발생과 관련해서는
TDZ(Temporal Dead Zone)의 개념을 알면 좋다. 변수를 선언하는 라인 이전에 해당 변수가 있다면 이는 TDZ 영역에 포함되며, 참조 에러(Reference Error)를 발생시켜 접근(변수 사용)을 금지한다.
JavaScript에는 다양한 data type이 존재한다. ECMAScript Standard는 7가지 Primitive data type과 Object로 아래와 같이 총 8가지 Data type을 정의한다.
참고로 object와 function은 언어의 다른 기본 요소이다. 객체는 값을 위한 container고, 함수는 애플리케이션이 수행할 수 있는 절차(procedure)이다.
BooleannullundefinedNumberBigintStringSymbolObject논리적인 요소를 나타내는 자료형으로, true와 false의 두 가지 값이 존재한다.
typeof true; // 'boolean'
1 === 1; //true
1 > 3; // false
const isNumberOdd = (5 % 2 == 0);
isNumberOdd; // true
어떤 값이 비어있음을 의도적으로 표현할 때 사용한다.
typeof null; // 'object'
let nullVar = null;
nullVar === null; // true
JS에는 null 자료형 식별자를 typeof 함수를 이용해 확인할 때 잘못된 자료형을 반환하는 버그가 있다.
해당 버그는 매우 오래된 버그이므로 고칠 경우, typeof를 사용하는 모든 웹사이트에 영향을 끼칠 수 있어 수정이 불가능하다고 한다.
따라서 변수가 null임을 확인하기 위해서는 값을 직접 비교하여야 한다.
값이 정의(할당)되어 있지 않은 경우 가지는 최상위 속성이다.
typeof undefined; // 'undefined'
let undefVar;
undefVar; // undefined
정수 또는 실수형 숫자가 해당되며, number 자료형에는 이 외에도 Infinity와 NaN(Not a Number)도 포함된다. 두 값은 숫자가 아닌 값을 숫자로 변환하거나, 0으로 나누는 연산을 수행하는 경우 발생한다.
typeof number; // 'number'
0 / 0; // NaN
3 / (-0); // -Infinity
3 / 0; // Infinity
typeof(3 / 0); // 'number'
typeof(0 / 0); // 'number'
임의 정밀도 방식으로 정수를 나타낼 수 있는 숫자 데이터 타입으로, 숫자 뒤에 n을 붙인다.
typeof 11n; // 'bigint'
문자열을 저장하는 자료형이다. 큰따옴표 또는 작은따옴표로 값을 묶어서 표현한 경우 string형이 된다. 또한, 문자열 내에 감싸는 문자 등이 포함되어 있는 경우 역슬래시(\)를 이용해 escape 시켜야 한다.
typeof "Hello JavaScript"; // 'string'
let name = "이참";
typeof name; // 'string'
ECMAScript 2015에 도입된 data type으로, instance가 고유하고 불변인 데이터 타입이다. 심볼은 객체에 속성을 추가할 때 고유한 키를 부여하여 다른 코드와 충돌하지 않도록 할 때 많이 쓰이며, 모든 Symbol() 호출은 각각 고유한 심볼을 반환하는 것이 보장된다.
let z = Symbol("main");
typeof z; // 'symbol'
const sym1 = Symbol();
const sym2 = Symbol("foo");
const sym3 = Symbol("foo");
sym2 === sym3; // false
let a = Symbol.for("key");
let b = Symbol.for("key");
a === b; // true, Symbol.for 호출은 주어진 값에 대해 같은 symbol을 반환한다.
key와 value를 가지는 자료형이다. key는 같은 계층에서 유일한 문자열이어야 하고, value에는 모든 종류(자료형)의 값이 할당될 수 있다. key를 통해 value에 접근할 수 있다.
객체 내부에 또 다른 객체가 포함될 수 있어 hierarchial data를 형성할 수 있다. 또한, 객체의 key에 여백(스페이스), 대쉬(-), 특수문자(*) 등 일반적인 변수명을 선언할 때 허용되지 않는 문자열을 사용할 경우 반드시 obj['key'] 와 같은 표현식을 사용해야 참조가 가능하다.
const person = {
name: '이참',
age: 24,
'favorite food': 'matcha'
};
typeof person; // 'object'
person.age; // 24
person['age']; //24
person.hobby; //undefined
person.'favorite food'; // Uncaught SyntaxError: Unexpected string
person['favorite food']; // 'matcha'
왜 array가 공식 문서에는 언급되어있지 않은지 의문이지만, array도 추가적으로 포함해 설명하도록 하겠다.
배열은 Index를 가지는 복수의 자료를 저장할 수 있는 자료구조로, 순서가 있다. JS에서는 각 원소의 자료형에 제한이 없어 서로 다른 자료형의 원소를 하나의 배열에 저장할 수 있다. 또한 배열의 크기가 정해져있지 않아 각종 method를 통해 원소의 자유로운 삽입과 삭제가 가능하다.
const arr = [0, 1, 1.5, true, 'hungry'];
typeof arr; // 'array'
arr[3]; // true
arr[4]; // 'hungry'
arr[5]; // undefined
JavaScript에서 truthy와 falsy는 boolean context에서 value들이 어떻게 evaluate되는지를 의미한다. 대표적 truthy 값은 true, falsy 값은 false이며, 조건문에서 자주 쓰이므로 알아두면 좋다.
falsy한 값에는 boolean primitive인 false를 포함하여 undefined, null, 0, ""(빈 문자열), NaN 등이 존재하며, 이들은 조건문 내에서 false로 취급된다.
위에 언급한 falsy 이 외에는 전부 truthy하게 취급된다고 생각하면 된다.
이번 시간에는 변수 선언 키워드와 Scope, Hoisting, Data Type과 Truthy & Falsy에 대해 알아보았다. TDZ나 closure등의 중요한 개념과 Naming Rule(Naming Convention) 등도 잠깐 등장했는데, 이에 대해서는 다른 개념들도 차근차근 공부하며 다루고자 한다.
다음 시간에는 연산자와 control flow(조건문 및 반복문) 등에 대해 알아보자.