JavaScript Variables
자바스크립트 변수 (JavaScript Variables) 완벽 가이드
- *자바스크립트(JavaScript)**는 웹 개발에서 가장 기본적이고 중요한 요소 중 하나인 **변수(Variables)**를 통해 데이터를 저장하고 조작합니다. 이 가이드에서는 자바스크립트 변수의 개념부터 선언 방법, 스코프, 호이스팅, var, let, const의 차이점 등 다양한 주제를 다루어 자바스크립트 변수를 효과적으로 활용할 수 있도록 도와드립니다.
1. 자바스크립트 변수란?
- *변수(Variable)**는 데이터를 저장할 수 있는 메모리 공간의 이름입니다. 자바스크립트에서는 변수를 사용하여 데이터를 저장하고, 그 데이터를 프로그램 내에서 재사용하거나 조작할 수 있습니다.
1.1. 변수의 개념
- 데이터 저장: 변수는 숫자, 문자열, 객체, 배열 등 다양한 데이터를 저장할 수 있습니다.
- 재사용 가능: 한 번 선언된 변수는 여러 번 사용할 수 있으며, 필요에 따라 값을 변경할 수 있습니다.
- 식별자: 변수는 식별자를 통해 참조됩니다. 식별자는 변수의 이름을 의미합니다.
2. 변수 선언 방법: var, let, const
자바스크립트에서는 변수를 선언할 때 var
, let
, const
키워드를 사용합니다. 각 키워드는 변수의 특성과 동작 방식에 따라 다르게
동작합니다.
2.1. var
// var를 사용한 변수 선언
var name = "Alice";
console.log(name); // 출력: Alice
// var는 재선언과 재할당이 가능합니다
var name = "Bob";
console.log(name); // 출력: Bob
name = "Charlie";
console.log(name); // 출력: Charlie
- 스코프: 함수 스코프(Function Scope)를 가집니다.
- 호이스팅: 변수 선언이 호이스팅되어, 선언 전에 접근할 수 있습니다.
- 재선언 및 재할당: 같은 스코프 내에서 재선언과 재할당이 가능합니다.
2.2. let
// let을 사용한 변수 선언
let age = 25;
console.log(age); // 출력: 25
// let은 재선언이 불가능하지만, 재할당은 가능합니다
// let age = 30; // SyntaxError: Identifier 'age' has already been declared
age = 30;
console.log(age); // 출력: 30
- 스코프: 블록 스코프(Block Scope)를 가집니다.
- 호이스팅: 선언 전에 접근할 수 없으며, 일시적 사각지대(Temporal Dead Zone)에 있습니다.
- 재선언 불가, 재할당 가능: 같은 스코프 내에서 재선언은 불가능하지만, 재할당은 가능합니다.
2.3. const
// const를 사용한 상수 선언
const PI = 3.14159;
console.log(PI); // 출력: 3.14159
// const는 재선언과 재할당이 모두 불가능합니다
// const PI = 3; // SyntaxError: Identifier 'PI' has already been declared
// PI = 3; // TypeError: Assignment to constant variable.
- 스코프: 블록 스코프(Block Scope)를 가집니다.
- 호이스팅: 선언 전에 접근할 수 없으며, 일시적 사각지대에 있습니다.
- 재선언 및 재할당 불가: 같은 스코프 내에서 재선언과 재할당이 모두 불가능합니다.
- 불변성: 객체나 배열을 선언할 때, 변수 자체는 불변이지만 객체의 속성이나 배열의 요소는 변경할 수 있습니다.
const person = {
name: "Alice",
age: 25
};
// 객체의 속성은 변경 가능
person.age = 26;
console.log(person.age); // 출력: 26
// 전체 객체를 재할당하려 하면 에러 발생
// person = { name: "Bob", age: 30 }; // TypeError: Assignment to constant variable.
3. 변수 스코프 (Scope)
변수의 **스코프(scope)**는 변수가 접근 가능한 범위를 의미합니다. 자바스크립트에서는 주로 글로벌 스코프, 함수 스코프, 블록 스코프로 나뉩니다.
3.1. 글로벌 스코프 (Global Scope)
글로벌 스코프는 코드 전체에서 접근 가능한 스코프입니다. var
로 선언된 변수는 함수 밖에서 선언되면 글로벌 스코프를 가지며, 브라우저 환경에서는 window
객체의 속성이 됩니다.
var globalVar = "전역 변수";
function showGlobalVar() {
console.log(globalVar); // 출력: 전역 변수
}
showGlobalVar();
console.log(window.globalVar); // 출력: 전역 변수 (브라우저 환경)
3.2. 함수 스코프 (Function Scope)
함수 스코프는 함수 내에서만 접근 가능한 스코프입니다. var
로 선언된 변수는 함수 내에서 선언되면 해당 함수 내에서만 유효합니다.
function myFunction() {
var functionVar = "함수 스코프 변수";
console.log(functionVar); // 출력: 함수 스코프 변수
}
myFunction();
console.log(functionVar); // ReferenceError: functionVar is not defined
3.3. 블록 스코프 (Block Scope)
블록 스코프는 {}
로 감싸진 블록 내에서만 접근 가능한 스코프입니다. let
과 const
로 선언된 변수는 블록 스코프를 가집니다.
{
let blockVar = "블록 스코프 변수";
const blockConst = "블록 상수";
console.log(blockVar); // 출력: 블록 스코프 변수
console.log(blockConst); // 출력: 블록 상수
}
console.log(blockVar); // ReferenceError: blockVar is not defined
console.log(blockConst); // ReferenceError: blockConst is not defined
4. 호이스팅 (Hoisting)
- *호이스팅(Hoisting)**은 자바스크립트가 변수 선언을 코드의 최상단으로 끌어올리는 동작을 말합니다. 이는 변수 선언이 코드의 어디에 위치하든지 간에, 해당 스코프 내에서 변수 선언이 최상단으로 끌어올려지는 것처럼 동작함을 의미합니다.
4.1. var의 호이스팅
var
로 선언된 변수는 선언부만 호이스팅되고, 초기화는 선언된 위치에서 이루어집니다. 따라서 변수 선언 전에 접근하면 undefined
가 됩니다.
console.log(a); // 출력: undefined
var a = 10;
console.log(a); // 출력: 10
위 코드는 다음과 같이 해석됩니다:
var a;
console.log(a); // 출력: undefined
a = 10;
console.log(a); // 출력: 10
4.2. let과 const의 호이스팅
let
과 const
로 선언된 변수는 호이스팅되지만, **일시적 사각지대(Temporal Dead Zone, TDZ)**에 있게 되어, 변수 선언 전에 접근하면
ReferenceError
가 발생합니다.
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 20;
console.log(c); // ReferenceError: Cannot access 'c' before initialization
const c = 30;
5. var, let, const의 차이점
var
, let
, const
는 변수를 선언할 때 사용하는 키워드로, 각각의 특성과 동작 방식이 다릅니다. 이를 이해하면 보다 안전하고
효율적인 코드를 작성할 수 있습니다.
5.1. 스코프
- var: 함수 스코프
- let, const: 블록 스코프
5.2. 호이스팅
- var: 선언과 초기화가 호이스팅됨 (초기화는 선언 위치에서)
- let, const: 선언만 호이스팅되고, 초기화는 TDZ에서 이루어짐
5.3. 재선언과 재할당
- var:
- 재선언: 가능
- 재할당: 가능
- let:
- 재선언: 불가능
- 재할당: 가능
- const:
- 재선언: 불가능
- 재할당: 불가능
5.4. 사용 권장
- var: 가능하면 사용하지 않는 것이 좋습니다. 스코프와 호이스팅의 복잡성으로 인해 버그가 발생하기 쉬움.
- let: 값이 변할 수 있는 변수에 사용.
- const: 값이 변하지 않는 상수에 사용.
6. 변수 이름 규칙과 관례
변수 이름은 코드의 가독성과 유지보수성을 높이는 데 중요한 역할을 합니다. 올바른 변수 이름을 사용하는 것은 코드의 의미를 명확하게 전달합니다.
6.1. 변수 이름 규칙
- 문자, 숫자, 언더스코어(_), 달러 기호($)만 사용 가능
- 숫자로 시작할 수 없음
- 예약어 사용 금지 (
let
,const
,var
,function
,class
등) - 대소문자 구분
6.2. 변수 이름 관례
-
카멜 표기법(Camel Case): 여러 단어로 이루어진 변수 이름을 작성할 때 첫 단어는 소문자로 시작하고, 이후 단어의 첫 글자를 대문자로 작성.
let userName = "Alice"; let totalAmount = 100;
-
의미 있는 이름 사용: 변수의 목적이나 역할을 명확하게 나타내는 이름을 사용.
let count = 10; // 단순히 숫자를 저장 let userCount = 10; // 사용자 수를 저장
-
약어 사용 피하기: 약어는 가독성을 떨어뜨릴 수 있으므로 피하는 것이 좋습니다.
let usrNm = "Alice"; // 나쁜 예 let userName = "Alice"; // 좋은 예
6.3. 상수 이름 관례
const
로 선언된 상수는 일반적으로 대문자와 언더스코어를 사용하여 작성.
const MAX_USERS = 100;
const API_URL = "<https://api.example.com>";
7. 변수 초기화와 재할당
변수를 선언할 때 초기값을 할당하거나, 이후에 값을 재할당할 수 있습니다.
7.1. 초기화
변수를 선언하면서 동시에 초기값을 할당할 수 있습니다.
let score = 85;
const PI = 3.14159;
7.2. 재할당
let
과 var
로 선언된 변수는 값을 재할당할 수 있습니다.
let score = 85;
score = 90; // 재할당 가능
var age = 25;
age = 30; // 재할당 가능
const
로 선언된 변수는 값을 재할당할 수 없습니다.
const PI = 3.14159;
PI = 3.14; // TypeError: Assignment to constant variable.
7.3. 변수 초기화 없이 선언
변수를 선언만 하고 초기화하지 않으면, var
는 undefined
, let
과 const
는 선언만 되어 있고 초기화되지
않은 상태로 남습니다.
var a;
console.log(a); // 출력: undefined
let b;
// console.log(b); // ReferenceError: Cannot access 'b' before initialization
const c;
// console.log(c); // SyntaxError: Missing initializer in const declaration
8. 불변성과 가변성
const
로 선언된 변수는 재할당이 불가능하지만, 객체와 배열의 속성은 변경할 수 있습니다. 이를
**불변성(Immutability)**과 **가변성(Mutability)**이라 합니다.
8.1. 불변 객체
객체의 속성을 변경할 수 없도록 만들려면 Object.freeze()
를 사용할 수 있습니다.
const person = Object.freeze({
name: "Alice",
age: 25
});
person.age = 30; // 무시됨
console.log(person.age); // 출력: 25
8.2. 가변 객체
객체의 속성은 변경할 수 있습니다.
const person = {
name: "Alice",
age: 25
};
person.age = 30;
console.log(person.age); // 출력: 30
9. 변수 타입 (Type of Variables)
자바스크립트는 동적 타이핑(Dynamic Typing) 언어로, 변수의 타입을 명시적으로 선언하지 않고도 다양한 타입의 값을 저장할 수 있습니다. 변수의 타입은 할당된 값에 따라 자동으로 결정됩니다.
9.1. 원시 타입 (Primitive Types)
-
Number: 숫자를 저장합니다.
let num = 42; let price = 19.99;
-
String: 문자열을 저장합니다.
let greeting = "Hello, World!"; let name = 'Alice';
-
Boolean: 참(true) 또는 거짓(false)을 저장합니다.
let isActive = true; let isCompleted = false;
-
Undefined: 값이 할당되지 않은 변수를 나타냅니다.
let x; console.log(x); // 출력: undefined
-
Null: 의도적으로 비어 있음을 나타냅니다.
let y = null; console.log(y); // 출력: null
-
Symbol: 고유하고 변경 불가능한 값을 생성할 때 사용됩니다.
let sym = Symbol("id");
-
BigInt: 매우 큰 정수를 저장할 때 사용됩니다.
let bigNumber = 9007199254740991n;
9.2. 참조 타입 (Reference Types)
-
Object: 키-값 쌍의 집합을 저장합니다.
let person = { name: "Alice", age: 25 };
-
Array: 순서가 있는 데이터 목록을 저장합니다.
let fruits = ["Apple", "Banana", "Cherry"];
-
Function: 함수 자체를 변수에 저장할 수 있습니다.
function greet() { console.log("Hello!"); } let sayHello = greet; sayHello(); // 출력: Hello!
9.3. 타입 확인
typeof
연산자를 사용하여 변수의 타입을 확인할 수 있습니다.
let a = 10;
let b = "Hello";
let c = true;
let d;
let e = null;
let f = Symbol("id");
let g = 9007199254740991n;
console.log(typeof a); // 출력: "number"
console.log(typeof b); // 출력: "string"
console.log(typeof c); // 출력: "boolean"
console.log(typeof d); // 출력: "undefined"
console.log(typeof e); // 출력: "object" (JavaScript의 버그)
console.log(typeof f); // 출력: "symbol"
console.log(typeof g); // 출력: "bigint"
10. 변수 관련 기타 개념
10.1. 비구조화 할당 (Destructuring Assignment)
비구조화 할당을 사용하면 배열이나 객체의 값을 간편하게 변수에 할당할 수 있습니다.
// 배열 비구조화
let [a, b] = [1, 2];
console.log(a); // 출력: 1
console.log(b); // 출력: 2
// 객체 비구조화
let person = { name: "Alice", age: 25 };
let { name, age } = person;
console.log(name); // 출력: Alice
console.log(age); // 출력: 25
// 기본값 설정
let [x = 10, y = 20] = [5];
console.log(x); // 출력: 5
console.log(y); // 출력: 20
let { a = 1, b = 2 } = { a: 3 };
console.log(a); // 출력: 3
console.log(b); // 출력: 2
10.2. 스프레드 연산자 (Spread Operator)
스프레드 연산자(...
)를 사용하면 배열이나 객체를 펼쳐서 복사하거나 결합할 수 있습니다.
// 배열 복사
let fruits = ["Apple", "Banana"];
let moreFruits = [...fruits, "Cherry"];
console.log(moreFruits); // 출력: ["Apple", "Banana", "Cherry"]
// 객체 복사
let person = { name: "Alice", age: 25 };
let updatedPerson = { ...person, age: 26 };
console.log(updatedPerson); // 출력: { name: "Alice", age: 26 }
10.3. 템플릿 리터럴 (Template Literals)
템플릿 리터럴을 사용하면 문자열 내에 변수를 쉽게 삽입할 수 있습니다.
let name = "John";
let age = 30;
// 기존 문자열 연결 방식
let message = "이름: " + name + ", 나이: " + age + "살";
console.log(message); // 출력: 이름: John, 나이: 30살
// 템플릿 리터럴 사용
let messageTemplate = `이름: ${name}, 나이: ${age}살`;
console.log(messageTemplate); // 출력: 이름: John, 나이: 30살
11. 예외 처리 (Exception Handling)
변수 사용 중 발생할 수 있는 오류를 처리하기 위해 예외 처리 구문을 사용할 수 있습니다.
11.1. try-catch-finally
try {
let result = divide(10, 0);
console.log(result);
} catch (error) {
console.log("오류 발생:", error.message);
} finally {
console.log("예외 처리 완료");
}
function divide(a, b) {
if (b === 0) {
throw new Error("0으로 나눌 수 없습니다.");
}
return a / b;
}
// 출력:
// 오류 발생: 0으로 나눌 수 없습니다.
// 예외 처리 완료
- try: 오류가 발생할 가능성이 있는 코드를 감쌉니다.
- catch: 오류가 발생했을 때 실행할 코드를 정의합니다.
- finally: 오류 발생 여부와 관계없이 항상 실행되는 코드를 정의합니다.
11.2. throw 문
throw
문을 사용하여 의도적으로 예외를 발생시킬 수 있습니다.
function validateAge(age) {
if (age < 18) {
throw new Error("미성년자는 접근할 수 없습니다.");
}
console.log("성인입니다.");
}
try {
validateAge(16);
} catch (error) {
console.log("오류:", error.message);
}
// 출력:
// 오류: 미성년자는 접근할 수 없습니다.
12. 모듈화 (Modularity)
모듈화를 통해 코드를 논리적인 단위로 분리하여 관리할 수 있습니다. ES6부터 import
와 export
키워드를 사용하여 모듈을 정의하고 사용할 수 있습니다.
12.1. 모듈 내보내기 (export
)
// math.js
export function add(a, b) {
return a + b;
}
export const PI = 3.14159;
12.2. 모듈 가져오기 (import
)
// main.js
import { add, PI } from './math.js';
console.log(add(2, 3)); // 출력: 5
console.log(PI); // 출력: 3.14159
12.3. 기본 내보내기와 가져오기
// greet.js
export default function greet(name) {
return `안녕하세요, ${name}!`;
}
// main.js
import greet from './greet.js';
console.log(greet("Bob")); // 출력: 안녕하세요, Bob!
12.4. 별칭 사용
// math.js
export function add(a, b) {
return a + b;
}
// main.js
import { add as sum } from './math.js';
console.log(sum(4, 5)); // 출력: 9
13. ES6+ 특징
ECMAScript 2015(ES6)는 자바스크립트의 주요 업데이트로, 다양한 새로운 기능과 개선 사항을 도입했습니다. ES6 이후에도 ECMAScript는 지속적으로 업데이트되며, 최신 자바스크립트 기능을 사용하면 코드의 가독성과 효율성을 높일 수 있습니다.
13.1. 화살표 함수 (Arrow Functions)
화살표 함수는 더 간결한 함수 표현식을 제공합니다.
// 기존 함수 표현식
function add(a, b) {
return a + b;
}
// 화살표 함수 표현식
const add = (a, b) => a + b;
console.log(add(2, 3)); // 출력: 5
- 장점
- 더 짧은 문법
this
바인딩이 정적으로 결정됨
- 주의 사항
this
가 기존 함수와 다르게 동작할 수 있음- 생성자 함수로 사용할 수 없음
13.2. 클래스 (Classes)
클래스는 객체 지향 프로그래밍을 보다 쉽게 구현할 수 있게 도와줍니다.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`안녕하세요, 제 이름은 ${this.name}이고, 나이는 ${this.age}살입니다.`);
}
}
const person1 = new Person("Bob", 28);
person1.greet(); // 출력: 안녕하세요, 제 이름은 Bob이고, 나이는 28살입니다.
13.3. 템플릿 리터럴 (Template Literals)
템플릿 리터럴을 사용하면 문자열 내에 변수를 쉽게 삽입할 수 있습니다.
let name = "John";
let age = 30;
// 기존 문자열 연결 방식
let message = "이름: " + name + ", 나이: " + age + "살";
console.log(message);
// 템플릿 리터럴 사용
let messageTemplate = `이름: ${name}, 나이: ${age}살`;
console.log(messageTemplate);
13.4. 비구조화 할당 (Destructuring Assignment)
비구조화 할당을 사용하면 배열이나 객체의 값을 간편하게 변수에 할당할 수 있습니다.
// 배열 비구조화
let [a, b] = [1, 2];
console.log(a); // 출력: 1
console.log(b); // 출력: 2
// 객체 비구조화
let person = { name: "Alice", age: 25 };
let { name, age } = person;
console.log(name); // 출력: Alice
console.log(age); // 출력: 25
13.5. 모듈 (Modules)
모듈화를 통해 코드를 논리적인 단위로 분리하여 관리할 수 있습니다. import
와 export
를 사용하여 모듈을 정의하고 사용할 수 있습니다.
// math.js
export function add(a, b) {
return a + b;
}
export const PI = 3.14159;
// main.js
import { add, PI } from './math.js';
console.log(add(2, 3)); // 출력: 5
console.log(PI); // 출력: 3.14159
13.6. 기타 ES6+ 기능
- Promise: 비동기 작업을 관리하기 위한 객체.
- async/await: 비동기 코드를 동기식 코드처럼 작성할 수 있게 도와주는 구문.
- 스프레드 연산자 (Spread Operator): 배열이나 객체를 펼쳐서 복사하거나 결합할 수 있음.
- 레스트 파라미터 (Rest Parameters): 함수의 매개변수로 나머지 인수를 배열로 받을 수 있음.
- 이터레이터와 제너레이터 (Iterators and Generators): 반복 가능한 객체를 생성하고 제어할 수 있음.
- Symbol: 고유하고 변경 불가능한 데이터 타입.
- Map과 Set: 키-값 쌍과 중복 없는 값을 저장하는 컬렉션 타입.
14. 문법 오류와 디버깅
14.1. 문법 오류 (Syntax Errors)
- *문법 오류(Syntax Errors)**는 코드가 자바스크립트 문법을 준수하지 않을 때 발생합니다. 이러한 오류는 코드 실행 전에 컴파일러가 감지하며, 오류 메시지를 통해 문제를 알려줍니다.
예시: 누락된 괄호
function greet(name) {
console.log("Hello, " + name;
}
greet("Alice");
// SyntaxError: missing ) after argument list
14.2. 디버깅 (Debugging)
- *디버깅(Debugging)**은 코드의 오류를 찾아 수정하는 과정입니다. 자바스크립트에서는 브라우저의 개발자 도구를 활용하여 디버깅을 수행할 수 있습니다.
주요 디버깅 도구
- Console:
console.log()
,console.error()
등을 사용하여 변수 값과 메시지를 출력. - Breakpoints: 코드 실행을 특정 지점에서 일시 중지하여 상태를 검사.
- Watch Expressions: 특정 변수나 표현식의 값을 실시간으로 모니터링.
- Call Stack: 함수 호출의 순서를 추적.
예시: 브라우저 디버깅
function calculateTotal(price, quantity) {
let total = price * quantity;
console.log("총 합계:", total);
return total;
}
calculateTotal(100, 5);
- 개발자 도구 열기:
F12
키 또는Ctrl+Shift+I
단축키 사용. - Console 탭:
console.log()
를 사용하여 변수 값을 확인. - Sources 탭: 브레이크포인트를 설정하고, 코드 실행을 단계별로 추적.
15. 요약
- 변수 선언:
var
,let
,const
키워드를 사용하여 변수를 선언합니다. - 스코프: 변수는 글로벌, 함수, 블록 스코프를 가집니다.
- 호이스팅:
var
는 선언과 초기화가 호이스팅되며,let
과const
는 TDZ에 의해 선언 전에 접근할 수 없습니다. - var, let, const의 차이점: 스코프, 호이스팅, 재선언 및 재할당 가능 여부에서 차이가 있습니다.
- 변수 이름 규칙: 문법 규칙을 따르고, 의미 있는 이름을 사용하는 것이 중요합니다.
- 불변성과 가변성:
const
로 선언된 변수는 재할당이 불가능하지만, 객체나 배열의 속성은 변경할 수 있습니다. - 비구조화 할당과 스프레드 연산자: 배열과 객체의 값을 쉽게 변수에 할당하고, 복사하거나 결합할 수 있습니다.
- 모듈화:
import
와export
를 사용하여 코드를 논리적인 단위로 분리할 수 있습니다. - ES6+ 기능: 화살표 함수, 클래스, 템플릿 리터럴 등 다양한 최신 기능을 활용하여 코드를 더 간결하고 효율적으로 작성할 수 있습니다.
- 문법 오류와 디버깅: 문법 오류를 이해하고, 개발자 도구를 활용하여 효과적으로 디버깅할 수 있습니다.
자바스크립트 변수의 다양한 개념과 활용 방법을 이해하고, 실제 프로젝트에 적용함으로써 효율적이고 안정적인 웹 애플리케이션을 개발할 수 있습니다. 꾸준한 연습과 학습을 통해 자바스크립트 변수의 전문가가 되어보세요!
JavaScript의 변수는 프로그램의 데이터 흐름을 관리하는 데 필수적인 도구입니다. 올바른 변수 선언과 관리 방법을 숙지하여 더 나은 개발자로 성장해보세요!