본문 바로가기
JS/JS 공부는 다다익선 [모던자바스크립트]

JS 공부는 다다익선 - 3. 변수

by spare8433 2023. 9. 20.

1. 원시 타입 (primitive data type)

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

 

1.1 number

64비트 부동소수점 형(double-precision 64-bit floating-point format : -(2^53^ -1) 와 2^53^ -1 사이의 숫자값) 을 따른다. 정수만을 위한 타입이 없고 모든 수를 실수를 처리한다. 정수로 표시된다해도 사실은 실수다.

 

※ 프로그래밍 언어에서 실수는 일반적으로 소수를 가리킨다.

 

2진수, 8진수, 16진수 리터럴은 메모리에 동일한 배정밀도 64비트 부동소수점 형식의 2진수로 저장된다. 자바스크립트는 2진수, 8진수, 16진수 데이터 타입을 제공하지 않기 때문에 이들 값을 참조하면 모두 10진수로 해석된다.

 

3가지 특별한 값들도 표현할 수 있다.

  • Infinity : 양의 무한대
  • -Infinity : 음의 무한대
  • NaN : 산술 연산 불가(not-a-number)



1.2 string

문자열(String) 타입은 텍스트 데이터를 나타내는데 사용한다. 문자열은 0개 이상의 16bit 유니코드 문자(UTF-16) 들의 집합으로 대부분의 전세계의 문자를 표현할 수 있다.

 

자바스크립트의 문자열은 원시 타입이며 변경 불가능(immutable)하다. 이것은 한 번 문자열이 생성되면, 그 문자열을 변경할 수 없다

 

문자열은 배열처럼 인덱스를 통해 접근할 수 있다. 이와 같은 특성을 갖는 데이터를 유사 배열이라 한다.



var str = 'Hello';
str = 'world';

 

요약:

  • 첫번째 구문이 실행되면 메모리에 문자열 Hello가 생성
  • 식별자 str은 메모리에 생성된 문자열 Hello 의 메모리 주소를 가리킨다.
  • 두번째 구문이 실행되면 이전에 생성된 문자열 ‘Hello’을 수정하는 것이 아니라 새로운 문자열 world 를 메모리에 생성하고 식별자 str 은 이것을 가리킨다. (이때 문자열 Hello 와 world 는 모두 메모리에 존재하고 있다.)

 

결론: 변수 str은 문자열 ‘Hello’를 가리키고 있다가 문자열 ‘world’를 가리키도록 변경되었을 뿐이다.



1.3 boolean

불리언(boolean) 타입의 값은 논리적 참, 거짓을 나타내는 truefalse 뿐이다.

 

비어있는 문자열과 null, undefined, 숫자 0은 false로 간주된다.



1.4 undefined

undefined 타입의 값은 undefined 가 유일하다. 선언 이후 값을 할당하지 않은 변수는 undefined 값을 가진다. 즉, 선언은 되었지만 값을 할당하지 않은 변수에 접근하거나 존재하지 않는 객체 프로퍼티에 접근할 경우 undefined가 반환된다.

 

변수 선언에 의해 확보된 메모리 공간을 처음 할당이 이루어질 때까지 빈 상태(대부분 비어있지 않고 쓰레기 값(Garbage value)이 들어 있다)로 내버려두지 않고 자바스크립트 엔진이 undefined로 초기화한다.

 

변수의 값이 없다는 것을 명시하고 싶은 경우 undefined 를 할당하는 것이 아니라 null 을 할당한다.



1.5 null

null 타입의 값은 null이 유일하다. 자바스크립트는 대소문자를 구별(case-sensitive)하므로 null은 Null, NULL등과 다르다.

 

null 은 의도적으로 변수에 값이 없다는 것을 명시할 때 사용한다. 이는 변수가 기억하는 메모리 어드레스의 참조 정보를 제거하는 것을 의미하며 자바스크립트 엔진은 누구도 참조하지 않는 메모리 영역에 대해 가비지 콜렉션을 수행할 것이다.

 

함수가 호출되었으나 유효한 값을 반환할 수 없는 경우, 명시적으로 null 을 반환하기도 한다.

 

※ 타입을 나타내는 문자열을 반환하는 typeof 연산자로 null 값을 연산해 보면 null이 아닌 object가 나온다. 이는 자바스크립트의 설계상의 오류이다. 따라서 null 타입을 확인할 때 typeof 연산자를 사용하면 안되고 일치 연산자(===)를 사용하여야 한다.



1.6 symbol

심볼(symbol) 은 ES6에서 새롭게 추가된 7번째 타입으로 변경 불가능한 원시 타입의 값이다. 심볼은 주로 이름의 충돌 위험이 없는 유일한 객체의 프로퍼티 키(property key)를 만들기 위해 사용한다. 심볼은 Symbol 함수를 호출해 생성한다.

 

const mySymbol = Symbol("mySymbol"); // 심볼에 "mySymbol" 이라는 설명을 추가

const myObj = {
  name: "John",
  age: 30,
  [mySymbol]: "This is a Symbol property" // Symbol 속성 추가
};

console.log(myObj[mySymbol]); // "This is a Symbol property"



2. 객체 타입 (Object type, Reference type)

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

 

원시 타입(Primitives)을 제외한 나머지 값들(배열, 함수, 정규표현식 등)은 모두 객체이다. 또한 객체는 pass-by-reference(참조에 의한 전달) 방식으로 전달된다.



3. 동적 타이핑 (Dynamic Typing)

자바스크립트는 동적 타입(dynamic/weak type) 언어이다. 이것은 변수의 타입 지정(Type annotation)없이 값이 할당되는 과정에서 값의 타입에 의해 자동으로 타입이 결정(Type Inference)될 것이라는 뜻이다. 따라서 같은 변수에 여러 타입의 값을 할당할 수 있다. 이를 동적 타이핑(Dynamic Typing)이라 한다.



4. 변수 호이스팅(Variable Hoisting)

자바스크립트의 특징으로 모든 선언문은 호이스팅(Hoisting) 이루어진다.

호이스팅이란 var 선언문이나 function 선언문 등 모든 선언문이 해당 Scope 의 선두로 옮겨진 것처럼 동작하는 특성을 말한다. 즉, 자바스크립트는 모든 선언문(var, let, const, function, [function*], class)이 선언되기 이전에 참조 가능하다.

 

console.log(foo); // ① undefined
var foo = 123;
console.log(foo); // ② 123
{
  var foo = 456;
}
console.log(foo); // ③ 456



① 의 값이 undefined 이유

변수는 3단계에 걸쳐 생성된다.

1. 선언 단계(Declaration phase): 변수 객체(Variable Object)에 변수를 등록한다. 이 변수 객체는스코프가 참조하는 대상이 된다.

2. 초기화 단계(Initialization phase): 변수 객체(Variable Object)에 등록된 변수를 메모리에 할당한다. 이 단계에서 변수는 undefined로 초기화된다.

3. 할당 단계(Assignment phase): undefined 로 초기화된 변수에 실제값을 할당한다.

 

결론:

또한 var 키워드로 선언된 변수는 선언 및 초기화 단계가 동시 진행된다. 즉 변수가 등록되고 변수는 메모리에 공간을 확보한 후 undefined로 초기화되기 때문에 변수 선언문 이전에 변수에 접근하는 ① 의 경우 undefined 를 반환하게 된다.



③ 의 값이 456 인 이유

자바스크립트의 변수는 다른 C-family와는 달리 블록 레벨 스코프(block-level scope) 를 가지지 않고 함수 레벨 스코프(function-level scope) 를 갖는다.

 

※ 단, ECMAScript 6에서 도입된 let, const 키워드를 사용하면 블록 레벨 스코프를 사용할 수 있다.

 

  • 함수 레벨 스코프(Function-level scope): 함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 외부에서는 참조 불가하다 즉, 함수 내부에서 선언한 변수는 지역 변수이며 함수 외부에서 선언한 변수는 모두 전역 변수이다.

 

  • 블록 레벨 스코프(Block-level scope): 코드 블록 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조 불가하다

 

결론:

따라서 코드 블록 내의 변수 foo는 전역변수이므로 전역에 선언된 변수 foo에 할당된 값을 재할당하기 때문에 ③의 결과는 456이 된다.



참고


https://poiemaweb.com/js-data-type-variable