JS 데이터타입 및 메모리

이수빈·2024년 1월 4일
0

Html, Css, JS

목록 보기
5/7
post-thumbnail

변수

변수

  • 하나의 값을 저장하기 위한 매커니즘.
  • 연산을 통해 생성된 변수는 메모리에 저장되어 재사용이 가능함.
  • 여러개의 값 저장 > 배열,객체
  • 식별자(변수이름), 변수값으로 구성
  • 식별자는 값이 아니라, 메모리 주소값을 기억하고 있음 => 이를 통해 메모리에 접근하여 메모리에 저장된 값을 사용하는 것임.

변수는 3가지 단계를 거쳐서 생성됨
1. 선언 단계(Declaration phase) : 변수 객체(Variable Object)에 변수를 등록한다. 이 변수 객체는 스코프가 참조하는 대상이 된다.
2. 초기화 단계(Initialization phase) : 변수 객체(Variable Object)에 등록된 변수를 메모리에 할당한다. 이 단계에서 변수는 undefined로 초기화된다.
3. 할당 단계(Assignment phase) : undefined로 초기화된 변수에 실제값을 할당한다.

선언자 var vs let

var의 단점

  • 변수 중복선언 허용
var x =1;
var y =1;
var x =100;
var y; // 초기화 문이 없는 변수 선언문은 무시된다.
console.log(x,y) // 100,1 
  • 함수레벨 스코프만 지원 : block-level scope가 존재하지 않는다.
var x =1;

if(true){
var x = 10; //block level scope임.
}
console.log(x) // 10이 출력됨.
  • 변수 호이스팅 : 변수 선언(선언+초기화)이 코드가 실행되는 런타임 이전에 실행되는 것.(변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 특징)
console.log(score); //undefined  //Reference Error가 아님.

var score = 80; // 변수선언

console.log(score) // 80 
// 변수선언은 런타임 이전, 변수 할당은 런타임 이후에 실행됨.

console.log(score); // undefined

score = 80;
var score;

console.log(score); //80이 된다..

var의 단점을 보안한 let

  • let과 var의 가장 큰 차이점 : let은 선언과 초기화단계가 분리되어 진행됨.

  • 그래서 호이스팅이 발생하지 않는것처럼 동작함

  • 선언단계와 초기화단계가 분리되어 진행됨. 런타임 이전에 선언단계가 실행되지만,

  • 변수 선언문에 도달했을때 초기화단계가 실행됨 >> 초기화 단계 이전에 변수에 접근하려고 하면 참조에러가 발생함.

  • 일시적 사각지대 : 스코프 시작~ 초기화 시작지점(변수선언) 까지의 변수를 참조 할 수 없는 구간임.

  • 호이스팅이 되는데, 선언단계와 초기화 단계가 분리되었기 때문에 호이스팅이 발생하지 않는것처럼 동작하는것임.

console.log(foo) // Reference Error
//일시적 사각지대.
let foo;
console.log(foo) // undefined;

foo = 1;
console.log(foo) // 1
  • let의 장점

  • 변수 중복 선언 금지

let bar = 123;
let bar = 456; // SyntaxError 발생함.
  • block level scope지원
let foo = 1;
{
	let foo = 2;
	let bar = 3;
}

console.log(foo) // 1;
console.log(bar) // Reference Error

데이터 타입

  • 원시 타입 (primitive data type), 객체 타입 (object/reference type)으로 나뉨

  • 두 데이터 타입의 차이점은 메모리의 재할당 방식임.

  • 원시 타입의 값은 변경 불가능한 값(immutable value)이며 pass-by-value(값에 의한 전달) 이다.

  • 즉 불변값이라는 의미는 같은 값이 오직 하나만 존재한다는 뜻임.

  • 재할당시 pass by value 이므로, 메모리가 해제되고 새로운 call stack의 메모리값을 부여받음 => 쓰지않는 주소값은 가비지콜렉터에 의해 해제됨

boolean
null
undefined
number
string
symbol (ES6에서 추가)

  • 객체는 데이터와 그 데이터에 관련한 동작(절차, 방법, 기능)을 모두 포함할 수 있는 개념적 존재이다. 달리 말해, 이름과 값을 가지는 데이터를 의미하는 프로퍼티(property)와 동작을 의미하는 메소드(method)를 포함할 수 있는 독립적 주체이다.

  • 자바스크립트는 객체(object) 기반의 스크립트 언어로서 자바스크립트를 이루고 있는 거의 “모든 것”이 객체이다. 원시 타입(Primitives)을 제외한 나머지 값들(배열, 함수, 정규표현식 등)은 모두 객체이다. 또한 객체는 pass-by-reference(참조에 의한 전달) 방식으로 전달된다. => 즉 원시타입이 아닌것은 모두 객체

  • 재할당시 call stack의 주소값은 변경되지 않음 => pass by reference로 동작하기 때문에 call stack의 주소값을 타고 heap에 값을 직접 변경함.

메모리와 재할당

엔진구조

  • 자바스크립트 엔진은 Memory Heap 과 Call Stack 으로 구성되어 있습니다. 가장 유명한 것이 구글의 V8 Engine입니다. 자바스크립트는 단일 스레드 (sigle thread) 프로그래밍 언어인데, 이 의미는 Call Stack이 하나 라는 이야기입니다. 즉 멀티가 되지 않고, 하나씩 하나씩 처리한다는 의미임
    (싱글스레드인 이유 ? => callstack 이 하나라서)

  • Call Stack이란 ?

    • 원시 타입(숫자 등) 데이터가 저장된다.
    • 실행 콘텍스트(Execution Context)를 통해

      1)변수 식별자(이름) 저장,
      2) 스코프 체인 및 this 관리
      3) 코드 실행 순서 관리 등을 수행.

  • 메모리 Heap

    • 참조타입(객체 등) 데이터가 저장된다.
    • 메모리의 할당이 일어나곳.
    • 가변데이터(동적인 데이터 저장)

원시값의 할당, 재할당

  • 10이라는 값 자체는 원시 타입이므로 콜 스택에 저장된다.

  • 변수 a에는 10이 저장된 콜 스택 메모리의 주소값이 저장된다. 변수 식별자 a 자체는 콜스택 상의 '실행 컨텍스트(Execution Context)의 렉시컬 환경(Lexical Environment)'이라는 곳에 저장된다.

  • 원시타입 변수가 할당되면, 할당된 값은 콜스택에, 그 값을 가르키는 주소값은 변수에 저장됩니다. 만약, a = 20 으로 재할당하게 되면, 콜스택에 주소값을 변수에 저장함.

  • b = 30을 할당하면, 30을 call stack에 저장, + 주소값을 변수 b에저장. 참조되지 않는 데이터는 적절한 시점에 가비지컬렉터에 의해 해제됨.

  • 실제로는 callstack에 변수또한 메모리에 올라가야함.

  • 변수영역과 데이터영역을 분리하는 것의 장점?

  • 500개의 변수에 똑같은 숫자 5를 할당하는 상황을 생각해 보자. 각각의 변수마다 데이터를 할당하려면 숫자 데이터가 8바이트를 필요로 하기 때문에 (500*8)바이트를 써야 한다.
  • 그 대신 5를 별도의 공간에 한 번 저장하고 해당 주소만 가지고 있는다면, 주소 공간의 크기가 1이라고 가정했을 때 (500 + 8)바이트만 사용해도 된다. 이처럼 변수 영역과 데이터 영역을 분리하면 중복된 데이터에 대한 처리 효율이 높아진다.

let b = 5;
let c = b;
c = 7;

  • 이런식으로 데이터영역 재사용 가능함, 재할당시 새로운 데이터영역(callstack) 에 값이 할당되고, 식별자는 그 주소값을 들고있음

  • 동일한 데이터가 있고, 이를 할당한다면 ? => 메모리는 데이터를 재사용하고, 변수에 데이터주소값을 넣음

  • Q.어떻게 중복된 값이 있는것을 알 수 있을까?

참조값의 할당, 재할당

  • 배열, 객체, 함수 등은 참조 타입이므로 메모리 힙에 저장된다.

  • 참조타입 데이터가 저장된 메모리 힙의 주소값은 콜스택에 각각 저장된다.

  • 메모리힙의 주소 값이 저장된 콜 스택의 주소값은 각각 변수 b, c, d에 저장된다.마찬가지로, 변수 식별자 b, c, d 이름 자체는 콜스택 상의 '실행 컨텍스트(Execution Context)의 렉시컬 환경(Lexical Environment)'에 저장된다.

  • 보통 callstack의 주소를 참조해서 heap에 접근해 직접 데이터를 변경.

  1. 변수의 고유 식별자를 생성합니다.(“myArray”)

  2. 콜 스택의 메모리에 주소를 할당합니다.(런타임에 할당될 것입니다.)

  3. 힙에 할당된 메모리 주소를 콜스택의 값(value)으로 저장합니다.(런타임에 할당될 것입니다.)

  4. 힙의 메모리 주소에 할당된 값(빈 배열 [])을 저장합니다.

참조값의 프로퍼티 재할당

  • 그럼 만약 객체안에 객체가 들어있는 형태나 객체안에 원시값이 들어있는 경우 객체나 배열 안의 값들은 어떻게 저장이 될까?

  • obj라는 변수는 callstack에 주소값을 가리킨다. => callstack의 주소값에는 heap에 대한 참조를 가르킨다.

  • heap에서 동적으로 메모리할당이 일어나는데, 원시값이라면 이를 다시 callstack의 데이터 영역의 값을 가르키는 구조이고,

  • 프로퍼티가 다시 참조 type이라면 heap에서 재할당이 일어나는 방식이다.

  • 여기서 3이라는 원시값은 앞에서 callstack에 할당이 일어났으므로 프로퍼티를 선언할때도 재사용하는 방식이다.

  • “변경”이란, 메모리 주소의 변경을 의미합니다.
  • let 은 메모리 주소를 변경을 허락합니다.
  • const 는 메모리 주소를 변경할 수 없습니다.

ref)

profile
응애 나 애기 개발자

0개의 댓글