변수 생성 방법과 호이스팅
자바스크립트 엔진은 소스코드 평가 단계를 거쳐 실행 단계로 가게 되는데, 변수 생성은 평가 단계와 실행 단계에서 이루어진다.
변수 생성 단계
1. 선언 단계: 변수를 변수 객체에 등록
2. 초기화 단계: 변수를 메모리에 할당하고, undefined 로 초기화
3. 할당 단계: undefined 로 초기화된 변수에 실제로 값을 할당
변수 선언은 3가지 방법으로 가능하다 -> var / const / let
- var
- ES6 이전부터 존재했음
- 코드 평가단계에서 선언과 동시에 초기화 진행
- 코드 실행단계에서 값 할당 진행
console.log(a);
var = 1;
console.log(a);
/*
출력
undefined
1
*/
코드 평가시점에서 초기화가 되어있으므로, 변수의 할당문이 실행되기도 전에 참조가 가능하다 -> 호이스팅 (hoisting)
할당 전에는 undefined 를, 할당 후에는 1 이 출력되는 것을 볼 수 있다.
여기서 호이스팅이란?
모든 선언문이 해당 scope 의 최상단으로 끌어올려진 것처럼 동작하는 특성을 말한다.
변수 선언문에서 뿐만 아니라 함수 선언문에서도 발생하며 각각을 변수 호이스팅, 함수 호이스팅이라고 한다.
var 키워드의 단점
- 키워드의 생략 가능
- 중복 선언 가능
- 변수 호이스팅
- 전역 변수화 -> 무분별한 변수 접근
a = 1; // var 키워드를 생략
var a = 2; // 중복선언 가능
console.log(window.a); // 전역함수화
이런 var 키워드의 단점들로 인해 var 키워드 사용을 지양해야 함.
- const / let
- ES6 부터 나옴
- 코드 평가단계에서 선언만 진행
- 코드 실행단계에서 초기화와 값 할당 진행
console.log(a);
const a = 1;
/*
출력
ReferenceError: Cannot access 'a' before initialization
*/
console.log(b);
let b = 1;
/*
출력
ReferenceError: Cannot access 'b' before initialization
*/
코드 평가시점에서 선언만 진행되므로, 변수 할당문이 실행되기 전에 참조가 불가능하다. -> ReferenceError 발생
const / let 은 블록 레벨 스코프
- 코드 블록 내에서 접근 가능한 스코프
- 변수에 한정적으로 접근이 가능하므로 예측 가능한 범위 내에서 변수 변경이 일어남
그럼 이제 const 와 let 의 각각의 특징에 대해 살펴보자.
const
- 수정 불가능 (재할당 불가능) -> 상수 변수를 선언할 때 사용
- 무조건 값을 할당해야 함
const a; // 값 할당 x
console.log(a);
/*
출력
SyntaxError: Missing initializer in const declaration
*/
const a = 1;
a = 2; // 값 수정(재할당)
console.log(a);
/*
출력
TypeError: Assignment to constant variable.
*/
let
- 재할당 가능
- 값을 할당하지 않아도 생성 가능
let a; // 값 할당 x
console.log(a);
/*
출력
undefined
*/
a = 2; // 값 수정 (재할당)
console.log(a);
/*
출력
2
*/
자료형
컴퓨터에게 데이터의 종류를 알려주어서 데이터 종류에 맞는 로직처리를 할 수 있게 해주어야 한다.
여기서 말하는 데이터의 종류를 데이터 타입, 자료형이라고 한다.
자바스크립트의 데이터 타입은 크게 2가지
- 원시 타입 -> String, Number, BigInt, Undefined, Null, Boolean, Symbol
- 참조 타입 (Object type, Reference type)
- 원시 타입 (String, Number, BigInt, Undefined, Null, Boolean, Symbol)
- 값 변경이 불가능 (immutable value)
- 참조 형태로 전달되는 것이 아니라 값으로써 전달됨
원시 타입은 변수를 원시 값으로 초기화 할 때, 변수는 그 값을 직접 가리키고 있다. 이때, 변수는 해당 값을 저장하고 있는 메모리 위치를 가리킨다.
변수를 새로운 값으로 재할당할 경우, 새로운 메모리 공간에 새로운 값이 저장되고, 변수는 새로운 메모리 위치를 가리키도록 변경된다. 기존 메모리의 값은 변경되지 않는다.
Number Type
- 자바스크립트에는 하나의 숫자 타입만 존재 = Number
- 자바스크립트는 모든 숫자를 실수로 처리 (정수타입이 없음!)
- 배정밀도 64비트 부동소수점 형식을 따름
- Infinity & (-Infinity) : 무한대를 나타내는 숫자
- NaN : Not A Number 의 줄임말로 숫자가 아님을 나타냄
배정밀도 64비트 부동소수점 형식(IEEE 754) 은 전자기술자 협회의 부동소수점 표현방식 표준으로,
실수를 연산할 때 근사값으로 처리하기 때문에 0.1 + 0.2 = 0.3 이 아니다.
console.log(0.1+0.2);
/*
출력
0.30000000000000004
*/
참고로 IEEE 754 형식의 최소~최대값은 -(2^53) 부터 2^53 까지 이다.
BigInt
- 임의 정밀도로 정수를 나타낼 수 있는 자바스크립트 숫자 원시 값
- Number 의 최대값을 넘는 정수와도 안전하게 저장하고 연산 가능
- 다른 타입과 혼합하여 사용 불가능
Sting
- 텍스트 데이터를 나타낼 때 사용
- UTF-16 코드 단위의 시퀀스로 표현
- 원시값은 값은 불변하기 때문에 문자값도 불변
- ' ' 또는 "" 또는 `` (백틱) 으로 감싸서 문자열임을 표현
문자값은 불변하기 때문에 요소 변경이 불가능하다.
let foo = 'apple';
foo[0] = 'b';
console.log(foo);
/*
출력
apple
*/
백틱은 템플릿 리터럴 표기법이라고도 하며 ES6 이후부터 사용 가능하다.
백틱은 따옴표에서는 할 수 없었던 줄바꿈, 표현식 삽입 등의 문자열 처리 기능을 제공한다.
표현식 삽입은 String interpolation 이라고 하며, 아래와 같이 쓸 수 있다. 표현식은 문자열로 강제로 타입이 변환된다.
console.log(`My name is ${ 표현식 }`);
Boolean Type
- 논리적 데이터 유형
- 참 or 거짓의 값만 가질 수 있음
Undefined Type
- 변수를 선언한 후 값을 할당하지 않은 변수에 할당이 되는 값
- 개발자가 의도해서 Undefined 값을 넣을 수도 있음
let a; // 값 할당 x
console.log(a);
/*
출력
undefined
*/
Null Type
- 값이 없다는 것을 의도적으로 표현할 때 null 을 사용
- 이전에 참조되어있던 값을 의도적으로 참조하지 않겠다는 뜻으로도 사용
const a = 1;
let b = a; // a 라는 값을 참조함
console.log(b);
/*
출력
1
*/
b = null; // 의도적으로 값을 참조하지 않겠다
console.log(b);
/*
출력
null
*/
null 타입체크는 일치연산자 (===) 사용하기
null type 은 'object' 라고 나오는데, 이는 자바스크립트 내의 버그로,
null 타입체크는 typeof 연산자가 아니라 일치연산자를 활용해야 한다.
Symbol Type
- ES6 부터 추가된 타입
- 중복되지 않는 유니크한 값 -> 객체의 key 로 사용될 수 있음 / 클래스나 객체형식의 내부에서만 접근 할 수 있도록 전용 객체 속성의 키로 사용
- Symbol 함수를 호출하여 생성
- new 연산자를 사용하면 TypeError 발생
const a = {
[Symbol.for('apple')]: 'fruit',
};
console.log(a[Symbol.for('apple')]);
/*
출력
fruit
*/
const sym1 = Symbol();
const sym2 = Symbol('description');
const sym3 = Symbol('description');
console.log(sym1 === sym2);
console.log(sym2 === sym3);
/*
출력
false
false
*/
심볼은 생성할 때마다 유일한 값을 가지며, 동일한 설명으로 생성된 심볼도 서로 다른 값을 가진다. 이 때문에 심볼은 객체의 속성 키로 사용할 때도 충돌을 피할 수 있다.
- 참조 타입
- 원시 타입을 제외한 모든 것은 객체
- 참조방식으로 전달 (Pass by reference) -> 객체의 메모리 주소값이 전달된다
- 객체는 속성들을 변경할 수 있는 mutable
참조 방식으로 데이터가 전달될 경우, 중간에 의도치 않게 데이터가 변경될 수 있으므로 데이터의 복사본을 전달해야 한다.
객체 타입 (mutable)
- 다양한 타입의 값을 하나의 단위로 구성한 복합적인 자료구조
- 데이터(속성), 데이터에 관련한 동작(method)
- 힙 메모리에 저장
- 참조 방식으로 전달
- 여러 형태의 객체 타입 -> 일반 객체와 함수, 날짜, 인덱스 컬렉션, 키 컬렉션, ...
동적 타입 언어
자바스크립트는 동적 타입 언어로, 의도적으로 타입을 변환할 수도 있지만 의도와 상관없이 변경되기도 함!
- 의도적인 타입 변환: 명시적 타입 변환
- 의도와 상관없는 타입 변환: 암묵적 타입 변환
- 명시적 타입 변환
자바스크립트 객체에는 객체별로 타입을 변환시키는 정적 메소드를 가지고 있다.
- 값.toString() -> 문자열 타입으로 변환
- Number(값) -> 숫자 타입으로 변환
- Boolean (값) -> 불리언 타입으로 변환
- 암묵적 타입 변환
개발자가 의도하지 않았지만, 타입이 변경되는 경우
- 값 + "문자열" -> 문자열 타입으로 변환
- 값 * 1 -> 숫자타입으로 변환
- !!값 -> 불리언 타입으로 변환
console.log(1 + '2'); // '12'
console.log(1 * '2'); // 2
console.log(1 - '2'); // -1
console.log(!!0); // false
암묵적 타입변환은 개발자의 의도와 다르게 타입이 변환될 수 있으므로 많은 혼선을 일으킬 수 있다.
이를 해결하기 위해 아래의 방법을 사용
- 전달되는 시점마다 typeof 또는 일치연산자를 사용해서 타입 guard 를 구현
- 자바스크립트 superSet 타입스크립트 사용
'웹 > JavaScript' 카테고리의 다른 글
[JavaScript] 기초- 데이터처리2 (0) | 2024.07.30 |
---|---|
[JavaScript] 기초 - 데이터 처리1 (0) | 2024.07.29 |
Promise 객체 (0) | 2024.05.27 |
[JavaScript/자바스크립트] 모듈, pakage.json, pakage-lock.json (0) | 2024.05.18 |
JS 배열 Array (0) | 2024.01.05 |