본문 바로가기
JS

Variables (Primitive type, Reference Type, Casting)

by Hyeon_E 2024. 6. 5.

Variables(변수)

변수는 데이터를 할당하고 참조하기 위해 사용됨

자바스크립트 변수는 값을 할당하고 해당 값을 다른 부분에서 사용할 수 있도록 해줌

변수를 사용하면 데이터를 유연하게 다룰 수 있으며, 계산, 조건부 로직, 데이터 처리 등 다양한 작업을 수행할 수 있음

변수는 코드의 가독성을 높이고 유지보수를 용이하게 만들어 줌

변수를 사용하면 의도를 명확히 표현하고 코드를 조직화할 수 있음

 

▶ 변수 선언 방법의 역할

변수를 선언할 때 사용하는 명령문(Statement)은 var, let, const 세가지를 사용

(ES5 let과 const의 등장으로 var는 이제 사용하지 않음)

  • var: 오래된 변수 선언 방식으로 재선언, 재할당이 가능하며 함수 스코프를 가짐
  • let: 재선언을 불가능하지만 재할당이 가능하며 블록 스코프를 가짐
  • const: 상수로서 값을 할당하는 변수를 선언하는데 사용. 재선언, 재할당이 모두 불가능하며 블록 스코프를 가짐

 

스코프  차이 알아보기

스코프란

  • 식별자(변수, 함수, 클래스 등)에 접근할 수 있는 유효 범위를 뜻함
  • 스코프의 범위는 블록(중괄호) 또는 함수에 의해 나눠짐

각 변수 차이

var(함수 레벨 스코프)

function function_level() {
  if (true) {
    var name = '명수';
    console.log(name); // 명수
  }
  console.log(name); // 명수
}

function_level();
console.log(name); // ReferenceError: name is not defined

 

  • 함수 안에서 선언된 변수는 함수 내에서만 유효. 블록 내부, 외부에 관계 없이 유효
  • 함수 외부에서는 참조할 수 없음
  • 단점: 전역 함수 외부에서 생성한 변수는 모두 전역 변수가 됨(전역 변수를 남발할 가능성을 높임/안사용하는 이유)

 

let/const (블록 레벨 스코프)

function block_level() {
  if (true) {
    let name = '명수';
    console.log(name); // 명수
  }
  console.log(name); // ReferenceError: name is not defined
}

block_level();
console.log(name); // ReferenceError: name is not defined

 

  • 모든 코드 블록(중괄호) 내부에서 선언된 변수는 코드 블록 내부에서만 유효
  • 블록 외부에서는 참조할 수 없음

 

▶ 호이스팅(Hoisting)

호이스팅이란 변수 및 함수 선언이 스코프 내의 최상단으로 끌어올려지는 것을 말함

자바스크립트에서 호이스팅 동작 방식

  1. 자바스크립트 parser(파서)가 함수가 실행되기 전에 해당 함수 전체를 훑음
  2. 함수 내에 존재하는 변수와 함수 선언에 대한 정보를 기억하고 실행
  3. 사실 유효 범위는 함수 블록 안이었지만, 필요한 값들은 블록 위의 최상단으로 끌어올려짐
  4. 실제 코드가 끌어올려지는 것은 아니고 자바스크립트 parser(파서)가 내부적으로 끌어올려서 처리하는 것이기 때문에 실제 메모리 변화는 없음

var 선언문 호이스팅

console.log(name); // undefined

var name = '명수';
console.log(name); // 명수

 

변수가 선언되기 전에 참조했는데 에러가 발생되지 않고 undefined가 출력

이유는 코드 실행 전에 자바스크립트 내부에서 미리 변수 name을 선언해서 undefined로 초기화 되었기 때문

 

let/const 선언문 호이스팅

console.log(name); // ReferenceError: name is not defined

let name = '명수';
console.log(name); // 명수

 

let과 const의 경우 변수가 선언되기 전에 참조하면 에러가 발생

 

결론

var의 경우 변수를 선언함과 동시에 초기화가 이루어지지만, let과 const의 경우 선언만 하고 초기화는 하지 않음
초기화는 위에서부터 순차적으로 코드를 실행하는 과정에서 변수 선언문을 만났을 때 수행
따라서 위의 let/const 예시 코드에서는 선언은 되었으나 초기화를 하지 않았기 때문에 에러가 발생하는 것
선언과 초기화 사이에 일시적으로 변수를 참조할 수 없는 구간TDZ(Temporal Dead Zone)이라고 부름

 

따라서 var, let, const는 모두 호이스팅 되지만 TDZ 때문에 변수를 참조할 수 없는 구간이 생겨서 호이스팅이 동작하지 않는 것처럼 보이는 것

 

Primitive Type, Reference Type(원시형, 참조형)

▶ Primitive Type

원시형이란 값 자체가 변하지 않고 직접 저장되는 데이터 타입

  • Number
    • 64비트 부동 소수점 방식으로 표현
    • 64비트 중에서 53비트만 수를 저장하고 나머지는 소수점 자리와 기호를 저장(따라서 2^53-1까지 정확성 보장)
    • Number.MAX_SAFE_INTEGER에 2^53-1 = 9007199254740991 값이 상수로 저장
      • Number.MAX_SAFE_INTEGER에 어떤 값을 더해도 최대 9007199254745992값이 됨
      • 따라서 Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 (참이됨 싱기)
  • String
    • 한 문자당 16비트가 고정적으로 할당
    • 문자열은 배열이 아닌 유사배열(Array-Like Object)
      • 유사배열은 숫자 형태의 indexing이 가능함
      • 유사배열은 length 프로퍼티가 잇음
      • 유사배열은 배열의 기본 메소드를 사용할 수 없
  • Boolean
    • 논리적 데이터 유형
    • 참(true) 혹은 거짓(false)값 만을 가질 수 있음
    • 1비트의 크기 할당
    • 거짓 같은 값(Falsy): Boolean 문맥에서 false로 평가 되는 값(이외에는 모두 참)
      • false
      • 0
      • 빈문자열('')
      • undefined
      • null
      • NaN
  • undefined
    • 선언 이후 값이 할당되지 않은 변수를 undefined로 초기화(개발자도 의도적으로 값이 없는 것을 명시할때는 null사용)
  • Null
    • 의도적으로 값이 없음을 명시하기 위한 데이터 타입(변수에 연결된 메모리 주소 참조를 제거하겠다는 의미)
    • 이후 자바스크립트 엔진은 참조하지 않은 메모리 영역(null 할당을 통해 메모리 주소 참조가 제거된 변수)에 대해 가비지 컬렉션을 수행하게 됨
  • Symbol
    • ES6에 새롭게 추가
    • 이름 충돌 위험이 없는 고유한 값으로 만들기 위해 사용
      • Symbol("foo") === Symbol("foo"); // false
      • const sym = Symbol('foo');
        obj[sym] = '123';
        console.log(sym) //Symbol('foo')
    • 객체에 속성을 추가할 때 고유한 키를 부여하여 다른 코드와 충돌하지 않도록 할때 많이 쓰임
      • 추가한 속성은 일반적으로 접근할수 없으므로 약한 형태의 캡슐화 혹은 정보 은닉을 제공함
  • BigInt
    • Number의 정확성을 보장해주는 최댓값인 2^53-1보다 큰 수 저장, 연산 가능
    • 정수 끝에 n을 추가하거나 생성자를 호출하는 방식으로 가능(ex. 127n)
    • BigInt 타입의 수는 BigInt 타입의 수하고만 연산이 가능(논리연산과 문자열 연결은 예외)

 

▶ Reference Type

참조형이란 값 자체가 아닌 메모리 주소(참조)를 통해 데이터를 저장하고 접근하는 데이터 타입을 의미

원시형을 제외한 모든 값

  • Object
  • Array
  • Funtion
  • etc..

 

▶ 자바스크립트 엔진

자바스크립트 엔진

자바스크립트 엔진함수를 실행하는 Call stackHeap 메모리로 구성됨

  • 원시형의 값은 함수를 실행하는 Call stack에 저장
  • 참조형의 값Heap 메모리에 저장

▶ value 저장 방식

원시형 저장 방식

원시형 값은 Call stack에 저장

  1. 자바스크립트는 변수의 이름으로 고유의 식별자(unique identifier)를 생성
  2. 원시형 값의 크기는 고정되어 있기 때문에 그 크기만큼 할당된 call stack 메모리에 실제값을 저장함
  3. 생성된 식별자는 값 자체가 아니라 값이 저장된 stack 메모리 주소를 가리킴
  4. 변수에 새로운 값이 할당하게 되면 가리키고 있는 메모리 주소의 값이 변하는 것이 아니라 새로운 값이 할당된 메모리 주소를 가리킴
    • 새로운 값을 할당할 때 메모리 주소의 값이 변하게 되면 이전에 이 메모리 주소를 가리키는 변수의 값도 바뀌기 때문에 데이터의 신뢰성을 보장할 수 없음
    • 데이터의 신뢰성을 보장하기 위해 의 값은 immutable(불변)한 성질을 갖음
    • 이를 위해 값이 변하는 대신 새로운 값을 가진 메모리가 할당

 

참조형 저장 방식

참조형의 값은 Heap 메모리에 저장

  1. 참조형의 값은 가변적이며 크기가 매우 커질 수 있기 때문에 stack이 아닌 heap에 저장
  2. 참조형의 값이 새로 생성되면, 그 값은 새로 할당된 heap 메모리에 저장
  3. 원시형과 동일하게 stack에서는 값을 할당받는 변수의 이름으로 식별자가 생성
  4. 이 식별자는 stack에 새로 할당된 메모리 주소를 가리키는데, 이 메모리 주소의 값은 실제 물리형 값이 아니라 참조형 값이 저장된 heap 메모리의 주소(식별자 → stack 주소 → heap 메모리 주소 →  값)

!!주의해야 할 점은 값을 완전히 바꾸는 것과 단순히 property를 바꾸는 것은 다르다는 점

  • const 변수로 선언해도 값을 바꿀 수 있음(const 변수가 가리키는 stack의 메모리 주소값이 변한 것이 아니기 때문이다. 즉 참조형은 mutable(변하기 쉬운)한 성질을 갖음)
  • 즉 stack의 값은 변함없어야 함 → 같은 메모리 주소를 가리켜야 함(let으로 선언할 경우 다른 메모리 주소 할당 가능)
  • 새로 할당된 값을 const로 선언된 변수에 할당하게 되면, 새로운 메모리 주소를 stack의 메모리에 넣는 것이기 때문에 불가능
  • 바꿀 수 있는 것은 기존의 stack메모리 주소가 가리키고 있는 heap에 저장된 값이며, 바꿀 수 없는 것은 stack의 메모리 주소
  • 두 변수가 같은 값을 할당받을 경우, stack에서 동일한 heap 메모리 주소를 가리키기 때문에 값을 변경할 경우 같은 값을 가진 변수의 값이 모두 변함(즉 같은 것을 다른 이름으로 부르는 것과 같음)

 

Type Casting(형변환)

자바스크립트는 타입이 매유 유연한 언어. 형변환이란 변수의 기존 자료형이 다른 자료형으로 바뀌는 것을 의미

자바스크립트 엔진이 필요에 따라 암시적 변환을 혹은 개발자의 의도에 따라 명시적 변환을 실행함

 

▶ 암시적 형 변환(Implicit type conversion)

암시적 형 변환이란 자바스크립트 엔진에 필요에 따라 자동으로 데이터 타입을 변환시키는 것

 

산술연산자

서로 다른 자료형을 가지는 변수를 대상으로 산술 연산자를 사용했을 때, 산술연산을 위해 자바스크립트 엔진은 두 자료형을 공통된 자료형으로 통일

'2' + 2	//'22'

더하기(+) 연산자는 숫자보다 문자열이 우선시 되기 때문에, 숫자형이 문자형을 만나면 문자형으로 변환하여 연산됨

 

'22' - 2 // 20

다른 연산자(-*/%)는 숫자형이 문자형보다 우선시되기 때문에 더하기와 같은 문자형으로의 변환이 일어나지 않음

 

느슨한 비교 연산자(==)

서로 다른 자료형을 가지는 변수를 느슨한 비교 연산자로 비교할때, 자바스크립트 엔진양 측의 두 변수를 공통된 자료형으로 변환한 후 엄격한 비교 연산자(===)의 수행한 결과를 리턴

null == undefined // true 0 == 0
“0” == 0 // true 0 == 0
0 == false // true 0 == 0
“0” == false // true 0 == 0

 

각 타입별로 느슨한 비교 연산자를 했을때 형변환표

 

이중 부정(!!)

변수 앞에 이중 부정 연산자를 사용한 경우 자바스크립트 엔진변수 앞에 이중부정 연산자를 마주하면 해당 변수를 무조건 Boolean 자료형으로 강제 변환

이중 부정 연산자에 의해 암시적 형변환은 주로 자바스크립트에서 false로 여겨지는 Falsy값들을 활용하여 if문을 분기하는데 자주 사용됨

  • Falsy 값: 0인 숫자, null, undefined, NaN, 빈 문자열, 빈 객체
  • Falsy 값 외는 모두 true로 판단
!!3.14	//true
!!0	//false

 

▶ 명시적 형 변환(Explicit Type Conversion)

명시적 변환이란 개발자가 의도를 가지고 데이터 타입을 변환 시키는 것

 

특정 자료형 생성자를 사용한 명시적 형변환

변수를 Object()Stiring()Booelan()Number() 등의 특정 자료형의 생성자로 감싸는 경우, 개발자는 변수를 특정 자료형으로 쉽게 변환할 수 있음

let trans = 100; 			//Number
Object(trans); 				//100
console.log(typeof trans); //Object
String(trans); 			   //”100"
console.log(typeof trans); //String
Boolean(trans); 			//true
console.log(typeof trans); //Boolean

 

자료형 변환 함수를 사용한 명시적 형변

변수.toString()변수.toNumber()변수.toBoolean() 등의 특별한 자료형 변환 함수를 사용하여 변수를 특정 자료형으로 변환할 수도 있음

// 모든 자료형 -> String
변수.toString()
숫자.toString(base) // base 진법의 문자열로 해당 숫자 변환 디폴트 = 10

// 모든 자료형 -> Number
undefined.toNumber() // NaN
null.toNumber() // +0
true.toNumber() // 1
false.toNumber() // +0

// 모든 자료형 -> Boolean
falsy값.toBoolean() // false
그 외 값.toBoolean() // true

 

그 외에도 String 자료형에 제공되는 parseInt()parseFloat() 등의 특별한 함수를 사용해 자료형을 변환하는 방법도 있음

// 문자열 -> 숫자
parseInt('3.14')	//3
parseFloat('3.14')	//3.14

parseInt("문자열") // 문자열이 정수 외 포함시 NaN 반환
parseFloat("문자열") // 문자열이 정수 외 포함시 NaN 반환

 

 

참조

JavaScript의 타입과 자료구조

호이스팅을 곁들인 var,let,const의 차이

primite type, object type

ericagong.log

호우 아빠는 오늘도 코딩을 하지

'JS' 카테고리의 다른 글

Asynchronous (Web API - setTimeout, setInterval, XMLHttpRequest, Callback Queue)  (0) 2024.06.07
this  (1) 2024.06.05
JS, StructuredClone()  (1) 2024.04.26
JS, isNaN(), Number.isNaN()  (0) 2024.03.29
JS, 이벤트 바인딩(Event Binding)  (0) 2023.12.26

댓글