🔍 자바스크립트의 특징
1. 실행 방식
자바스크립트는 별도의 컴파일 과정 없이 실행되는 인터프리터 언어지만, 대부분 모던 자바스크립트 엔진은 성능 향상을 위해 일부 코드를 컴파일해 실행합니다.
| 컴파일러 언어 | 인터프리터 언어 | |
|---|---|---|
| 실행 방식 | 컴파일 타임에 코드 전체를 머신 코드로 변환 후 실행 | 런타임에 문 단위로 한 줄씩 바이트코드로 변환 후 실행 |
| 실행 파일 | ✅ 생성 | ❌ 생성 안함 |
| 코드 실행 속도 | 빠름 | 비교적 느림 |
2. 실행 환경
자바스크립트는 브라우저 또는 Node.js에서 실행할 수 있지만, 실행 목적과 제공하는 기능이 다릅니다.
| 브라우저 | Node.js | |
|---|---|---|
| 실행 목적 | 웹페이지를 브라우저 화면에 렌더링 | 브라우저 외부에서 자바스크립트 실행 |
| 실행 위치 | 클라이언트 | 서버 또는 로컬 |
| DOM API | ✅ 제공 | ❌ 미제공 |
| 파일 시스템 접근 | ❌ 불가능(보안상 제한) | ✅ 가능 |
🏷️ 변수 선언
변수(variable)는 프로그램이 값을 저장하고 참조할 수 있도록 메모리 공간에 붙인 이름입니다.
변수 선언은 값 저장을 위해 메모리 공간을 확보하고 변수 이름과 해당 메모리 주소를 연결해 값을 저장할 수 있게 준비하는 과정입니다. 자바스크립트 엔진은 변수 선언을 아래의 2단계에 거쳐 수행합니다.
1. 선언: 변수 이름을 실행 컨텍스트에 등록합니다.
실행 컨텍스트(Execution Context)
자바스크립트 코드가 실행되는 환경으로, 변수, 함수, 스코프, this 등의 정보를 관리하는 영역입니다. 변수 이름과 값은 실행 컨텍스트 내에 키/값 형식인 객체로 관리됩니다.
2. 초기화: 메모리 공간 확보 후 undefined를 할당합니다.
초기화를 거치지 않으면, 메모리 공간에는 이전에 사용했던 쓰레기 값이 남아 있을 수 있습니다.
👉 var 변수는 선언과 초기화가 동시에 진행됩니다.
🎈 변수 호이스팅
호이스팅(Hoisting)은 선언문이 코드의 맨 위로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징입니다.
자바스크립트 엔진은 모든 선언문(변수, 함수 등)을 코드 실행 전에 먼저 찾아 처리합니다. 따라서 선언문의 위치와 상관없이 변수를 참조할 수 있습니다.
👉 선언문은 소스코드 평가 단계에서 먼저 실행되고, 값의 할당은 런타임에 이루어집니다.
⚖️ 변수 선언 방식 비교
| var | let | const | |
|---|---|---|---|
| 스코프 | 함수 스코프 | 블록 스코프 | 블록 스코프 |
| 재선언 | ✅ 가능 | ❌ 불가능 | ❌ 불가능 |
| 재할당 | ✅ 가능 | ✅ 가능 | ❌ 불가능 |
| 호이스팅 | ✅ 발생 (초기값 undefined) | ✅ 발생하지만 TDZ 적용 | ✅ 발생하지만 TDZ 적용 |
| 초기화 | ❌ 선택 사항 | ❌ 선택 사항 | ✅ 필수 |
TDZ(Temporal Dead Zone)
let과const로 선언된 변수가 호이스팅되더라도, 선언문 이전에는 초기화되지 않아 접근할 수 없는 구간을 의미하며, 이 구간에서 변수를 사용하면ReferenceError가 발생합니다.
👉 var로 선언한 전역 변수는 전역 객체의 프로퍼티로 등록됩니다.
🔢 데이터 타입
| 구분 | 데이터 타입 | 설명 |
|---|---|---|
| 원시 (Primitive) | number | 숫자 |
| bigint | 큰 정수 | |
| string | 문자열 | |
| boolean | 참/거짓 | |
| undefined | 값이 할당되지 않은 상태 | |
| null | 의도적으로 비어있는 값 | |
| symbol | 유일한 식별자 | |
| 참조 (Reference) | object | 일반 객체, 배열, 날짜 등 |
| function | 호출 가능한 함수 |
- null이
object로 출력되는 것은 자바스크립트 초기 구현 시의 버그입니다.
console.log(typeof null) // "object"- 선언되지 않은 식별자에
typeof를 사용하면ReferenceError없이undefined를 반환합니다.
console.log(typeof undeclared) // "undefined"- BigInt는 정수 전용 타입으로, 매우 큰 정수를 안전하게 다룰 수 있습니다.
n접미사나BigInt()생성자를 사용하며, 연산 시 다른 BigInt끼리만 계산할 수 있습니다.
const big = 9007199254740991n
const big2 = BigInt(123456789)🧮 헷갈리기 쉬운 연산자 모음
1. 할당 연산자
할당문은 값으로 평가되는 표현식으로, 할당된 값 자체를 반환합니다. 이 특징을 이용하면 여러 변수에 동일한 값을 한 번에 연쇄적으로 할당할 수 있습니다.
var x
console.log((x = 10)) // 10// 연쇄 할당은 오른쪽에서 왼쪽으로 순차적으로 평가됩니다.
// 예를 들어, a = b = c = 0은 실제로 a = (b = (c = 0))처럼 실행됩니다.
var a, b, c
a = b = c = 0
console.log(a, b, c) // 0 0 02. 비교 연산자
NaN은 자신과 일치하지 않는 유일한 값입니다. 값이 NaN인지 확인하려면 Number.isNaN()을 사용해야 합니다.
ES6에서 도입된 Object.is 메서드는 정확한 비교 결과를 반환합니다.
NaN === NaN // false
Number.isNaN(NaN) // true
0 === -0 // true
0 == -0 // true
Object.is(NaN, NaN) // true
Object.is(-0, +0) // false3. 쉼표 연산자
여러 표현식을 왼쪽에서 오른쪽으로 차례대로 평가하고, 마지막 표현식의 값만 반환합니다.
var x, y, z
;(x = 1), (y = 2), (z = 3) // 34. 논리합(||) & 논리곱(&&) 연산자
논리 연산자는 피연산자를 불리언으로 강제 변환하지 않고 그대로 반환합니다.
| 연산자 표현식 | 결과 | 설명 |
|---|---|---|
| true || anything | true | 첫 번째 값이 truthy이면 두 번째 값은 평가하지 않고 첫 번째 값을 반환 |
| false || anything | anything | 첫 번째 값이 falsy이면 두 번째 피연산자를 반환 |
| true && anything | anything | 첫 번째 값이 truthy이면 두 번째 피연산자를 반환 |
| false && anything | false | 첫 번째 값이 falsy이면 두 번째 값은 평가하지 않고 첫 번째 값을 반환 |
5. 옵셔널 체이닝(?.) 연산자
객체의 중첩된 속성에 접근할 때, 값이 null 또는 undefined인 경우 에러를 발생시키지 않고 undefined를 반환합니다.
var elem = null
var value = elem?.value
console.log(value) // undefined6. null 병합(??) 연산자
좌측 피연산자가 null 또는 undefined일 때만 우측 값을 반환합니다.
var foo = null ?? 'default string'
console.log(foo) // 'default string'📦 원시 값과 객체
인스턴스(Instance)
클래스라는 템플릿을 바탕으로 생성되어 메모리에 저장된 실제 객체입니다.
1. 원시 값
원시 값은 변경 불가능(Immutable)하며, 직접 수정할 수 없습니다. 값을 변경하려면 새로운 메모리 공간에 새 값을 저장하고 변수가 그 주소를 참조하도록 재할당해야 합니다. 이런 특성을 불변성(Immutability)이라고 합니다.
유사 배열 객체(Array-like object)
유사 배열 객체는 배열과 비슷하게
index와length속성을 가지고 있지만, 배열 메서드(Array.prototype)는 직접 사용할 수 없습니다.문자열도 유사 배열처럼 동작하여 인덱스로 접근 가능하고 반복문으로 순회할 수 있지만, 문자열 자체는 원시 값이므로 개별 문자를 수정할 수 없습니다.
const str = 'Hello'
console.log(str[0]) // "H"
console.log(str.length) // 5
for (const char of str) {
console.log(char)
}
// H e l l o
str[0] = 'h'
console.log(str) // "Hello" (변경되지 않음)값에 의한 전달(Pass by value)
함수에 원시 값을 전달할 때, 값 자체가 복사되어 전달되는 방식입니다. 따라서 함수 내부에서 값을 변경해도 원본 변수에는 영향이 없습니다.
2. 객체
객체는 변경 가능(Mutable)하며, 변수는 객체가 저장된 메모리 주소를 기억합니다.
var person1 = {
name: 'Lee',
}
var person2 = {
name: 'Lee',
}
console.log(person1 === person2) // false
console.log(person1.name === person2.name) // true참조에 의한 전달(Pass by reference)
객체의 속성을 수정하면 메모리 주소에 저장된 값이 변경되므로, 변수나 함수로 전달된 참조를 통해 원본 객체도 함께 변경됩니다.
참고 자료
『모던 자바스크립트 Deep Dive』, 이웅모 저, 위키북스