JavaScript

JavaScript - 자바스크립트란 무엇인가? (심화편-1 타입, 변수 등)

인어공쭈 2024. 9. 22. 11:51

자바스크립트의 타입과 깊은 개념들

자바스크립트는 동적 타입(dynamic typing)을 사용하는 언어로, 변수에 다양한 타입의 값을 할당할 수 있다. 이를 이해하면 자바스크립트의 독특한 동작과 그 안에서 발생할 수 있는 문제들을 해결하는 데 중요한 개념들을 파악할 수 있다. 이번 포스트에서는 자바스크립트의 타입과 관련된 여러 개념들을 하나의 흐름으로 살펴보자.

 

자바스크립트의 타입

자바스크립트의 데이터 타입은 크게 두 가지로 나눌 수 있다: **기본형(Primitive Type)**과 **참조형(Reference Type)**이다.

  1. 기본형(Primitive Type):
    • Number: 숫자를 표현하는 타입이다. 자바스크립트에서는 정수와 실수를 구분하지 않고 모두 Number로 취급한다.
    • String: 문자열을 나타낸다. 작은 따옴표('')나 큰 따옴표("")로 감싸서 표현한다.
    • Boolean: true 또는 false 값을 가진다.
    • Null: 의도적으로 '값이 없음'을 나타내는 타입이다.
    • Undefined: 값이 할당되지 않은 변수를 나타낸다.
    • BigInt: 매우 큰 정수를 표현할 수 있는 타입이다.
    • Symbol: 유일하고 변경 불가능한 값을 나타낸다.
  2. 참조형(Reference Type):
    • Object: 일반 객체
    • Array: 배열
    • Function: 함수
    • Map: 키-값 쌍을 저장하는 객체
    • Set: 중복 없는 값의 집합
    • Date: 날짜와 시간을 저장하는 객체
    • RegExp: 정규 표현식 객체
    • WeakMap: 약한 참조를 가진 Map
    • WeakSet: 약한 참조를 가진 Set
더보기

오브젝트의 메모리 참조 방식

 

자바스크립트에서 객체는 참조 타입이므로, 변수에 할당된 객체는 그 자체가 아닌 메모리 주소를 참조한다. 이는 객체를 다른 변수에 할당할 때, 그 변수도 동일한 메모리 주소를 가리키게 되어 원본 객체와 복사된 객체가 서로 영향을 미친다.

let obj1 = { key: 'value' };
let obj2 = obj1;
obj2.key = 'newValue';
console.log(obj1.key);  // 'newValue'

 

Map과 WeakMap의 차이

자바스크립트에서 Map WeakMap은 모두 키-값 쌍을 저장하는 객체지만, 몇 가지 중요한 차이점이 있다.

  • Map: 모든 키를 강하게 참조한다. 키로 사용된 객체가 메모리에서 수동으로 삭제되지 않는 한 계속 메모리에 남아 있다.
  • WeakMap: 키로 사용된 객체에 대해 **약한 참조(weak reference)**를 한다. 즉, 객체가 더 이상 참조되지 않으면 가비지 컬렉션에 의해 자동으로 메모리에서 해제될 수 있다. 이를 통해 메모리 누수를 방지할 수 있다.
let weakMap = new WeakMap();
let obj = {};
weakMap.set(obj, 'value');
obj = null;  // obj가 가비지 컬렉션에 의해 제거됨

 

Set과 WeakSet의 차이

자바스크립트에서 Set WeakSet은 모두 고유한 값을 저장하는 데이터 구조이지만, 몇 가지 중요한 차이점이 있다. 

Set

  • 데이터 타입: 모든 값(숫자, 문자열, 객체 등)을 저장할 수 있다.
  • 중복 허용: 중복된 값은 자동으로 제거된다.
  • 크기 확인: size로 저장된 값의 개수를 확인할 수 있다.
  • 이터레이션: forEach로 반복 가능하다.
let set = new Set();
set.add(1);
set.add(2);
console.log(set.size);  // 2

 

WeakSet

  • 데이터 타입: 객체만 저장할 수 있다.
  • 가비지 컬렉션: 객체가 더 이상 참조되지 않으면 자동으로 메모리에서 해제된다.
  • 크기 확인 불가: size나 이터레이션 불가능.
let weakSet = new WeakSet();
let obj = { a: 1 };
weakSet.add(obj);
obj = null;  // obj가 메모리에서 해제됨

 

 

 

 

0.1 + 0.2 ≠ 0.3? 부동소수점의 한계

자바스크립트에서 0.1 + 0.2 === 0.3이 false가 되는 현상은 자바스크립트가 숫자를 IEEE 754 표준에 따라 64비트 부동소수점으로 표현하기 때문이다. 이 표준은 정확한 소수를 표현하는 데 한계가 있어, 0.1과 0.2를 더한 결과는 정확히 0.3이 아닌 근사치로 표현된다.

해결 방법:

이 문제를 해결하려면 반올림이나 정확한 소수점 처리를 해야 한다. 예를 들어 toFixed() 메서드나 소수점 이동을 활용할 수 있다.

let result = (0.1 * 10 + 0.2 * 10) / 10;  // 0.3

 

Null과 Undefined의 차이

**null**은 의도적으로 "값이 없다"는 것을 표현할 때 사용되며, 명시적으로 할당할 수 있다. 반면 **undefined**는 변수가 선언되었지만 값이 아직 할당되지 않은 상태를 나타낸다.

  • Null: 프로그래머가 "이 변수는 의도적으로 비어 있다"라고 명시할 때 사용한다.
  • Undefined: 자바스크립트 엔진에서 기본적으로 할당되지 않은 변수를 가리킬 때 사용한다.

 

Symbol: 유일한 식별자

Symbol은 자바스크립트에서 고유하고 변경 불가능한 값을 나타내기 위해 도입된 타입이다. 주로 객체의 속성 키로 사용되며, 같은 이름의 Symbol을 생성하더라도 항상 유일한 값을 가진다.

let sym1 = Symbol('description');
let sym2 = Symbol('description');
console.log(sym1 === sym2);  // false, 서로 다른 Symbol

 

 

얕은 복사와 깊은 복사

자바스크립트에서는 객체나 배열을 복사할 때 두 가지 방식이 있다: 얕은 복사깊은 복사.

  • 얕은 복사: 객체의 참조를 복사하는 방식으로, 복사된 객체는 원본 객체와 같은 메모리 주소를 참조한다.
  • 깊은 복사: 객체의 모든 속성과 하위 객체까지 모두 복사하여, 복사된 객체가 원본 객체와 독립적으로 존재한다.

깊은 복사 방법:

  1. **JSON.stringify()**와 **JSON.parse()**를 사용하여 객체를 깊은 복사할 수 있다.
  2. 재귀 함수를 사용하거나, 라이브러리(예: Lodash의 cloneDeep)를 사용할 수 있다.

 

불변성이란 무엇인가?

**불변성(immutability)**은 객체나 데이터가 한 번 생성되면 그 값을 변경할 수 없다는 개념이다. 불변성은 데이터 변경으로 인한 예기치 않은 부작용을 방지하고, 코드를 보다 예측 가능하게 만든다. React와 같은 프레임워크에서는 불변성이 상태 관리에 중요한 역할을 한다.

객체의 가변성에 따른 문제점의 해결방법으로써 쓰이기도 한다. (원본은 계속 유지되어야될때)

 

불변성을 활용하는 방법

불변성을 유지하면서 객체를 변경하려면, 새로운 객체를 만들어 변경 사항을 적용해야 한다. 스프레드 연산자Object.assign을 사용하면 쉽게 객체를 복사하고 수정할 수 있다.

let obj1 = { a: 1, b: 2 };
let obj2 = { ...obj1, b: 3 };
console.log(obj2);  // { a: 1, b: 3 }

 

 

변수 선언

자바스크립트에서는 변수를 선언할 때 var, let, const 키워드를 사용할 수 있는데, 각각의 차이를 이해하는 것이 중요한 개념이다. 특히, ES6(ECMAScript 2015) 이후에 도입된 letconstvar에 비해 여러 면에서 더 안전하고 예측 가능한 동작을 제공한다.

var와 let의 차이

1. 스코프(Scope):

  • var: 함수 스코프(function scope)를 따른다. 즉, 함수 내에서만 유효하며, 블록 {} 내부에서 선언해도 함수 전체에서 접근할 수 있다.
  • let: 블록 스코프(block scope)를 따른다. 즉, {} 블록 내에서만 유효하며, 그 외부에서는 접근할 수 없다.
if (true) {
    var a = 10;
    let b = 20;
}
console.log(a);  // 10, var는 블록 밖에서도 접근 가능
console.log(b);  // ReferenceError, let은 블록 밖에서 접근 불가

 

2. 변수의 호이스팅(Hoisting):

  • var: 호이스팅이 발생해 변수 선언이 코드 상단으로 끌어올려진다. 하지만 선언된 변수는 undefined로 초기화되어, 선언 전에도 사용할 수 있다.
  • let: 호이스팅은 되지만 **TDZ(Temporal Dead Zone)**가 적용되어, 선언 이전에 변수를 사용할 경우 에러가 발생한다.

3. 재선언:

  • var: 같은 변수명을 여러 번 선언해도 에러가 발생하지 않는다.
  • let: 같은 변수명을 중복 선언할 경우 에러가 발생한다.

 

const 사용의 장점

  • 변수에 한 번 값이 할당된 후 그 값을 바꾸는 것을 방지하여, 코드의 예측 가능성을 높인다.
  • 코드 유지보수가 쉬워지고, 실수를 줄일 수 있다.
  • 주로 상수를 선언할 때 사용되며, 값이 변경되지 않을 변수임을 명확히 표현할 수 있다.

 

더보기

TDZ(Temporal Dead Zone)란 무엇인가?

TDZ(Temporal Dead Zone)는 자바스크립트에서 let이나 const로 선언된 변수가 초기화되기 전에 접근될 수 없는 구간을 의미한다. 코드가 실행될 때, 변수 선언은 호이스팅되지만, 실제로 값이 할당되기 전까지는 해당 변수를 참조할 수 없으며, 이 기간 동안 변수를 사용하려고 하면 ReferenceError가 발생한다.

 

반응형