연습장

6. Data type & Variable 데이터 타입과 변수 본문

JavaScript

6. Data type & Variable 데이터 타입과 변수

js0616 2024. 7. 5. 08:44

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

 

Data type & Variable | PoiemaWeb

변수는 값의 위치(주소)를 기억하는 저장소이다. 값의 위치란 값이 위치하고 있는 메모리 상의 주소(address)를 의미한다. 즉, 변수란 값이 위치하고 있는 메모리 주소(Memory address)에 접근하기 위해

poiemaweb.com

 

 

 

프로그래밍이란

변수를 통해 값을 저장하고 참조하며

연산자로 값을 연산, 평가하고

조건문과 반복문에 의한 흐름제어로 데이터의 흐름을 제어하고

함수로 재사용이 가능한 구문의 집합을 만들며

객체, 배열 등으로 자료를 구조화하는 것이다.

 

변수는 값의 위치(주소)를 기억하는 저장소이다.

값의 위치란 값이 위치하고 있는 메모리 상의 주소(address)를 의미한다.

즉, 변수란 값이 위치하고 있는 메모리 주소(Memory address)에 접근하기 위해 사람이 이해할 수 있는 언어로 명명한 식별자(identifier)이다.

 

 

 

C언어를 공부하면 포인터에 대한 개념이 나오는데 그걸 알면 조금 더 이해가 되는거같다. 

 

메모리에 값을 저장하기 위해서는 먼저 메모리 공간을 확보해야 할 메모리의 크기(byte)를 알아야한다. 

이는 값의 종류에 따라 확보해야 할 메모리의 크기가 다르기 때문이다. 

이때 값의 종류, 즉 데이터의 종류를 데이터 타입(Data Type)이라 한다.

 

 

C나 Java같은 C-family 언어 

  • 정적 타입(Static/Strong Type) 언어
  • 변수 선언 시 변수에 저장할 값의 종류를 사전에 타입 지정(Type annotation)

 

// 1byte 정수형: -128 ~ 127
char c;

// 4byte 정수형: -2,124,483,648 ~ 2,124,483,647
int num;
 

 

 

 

 

자바스크립트

  • 동적 타입(Dynamic/Weak Type) 언어
  • 변수의 타입 지정(Type annotation)없이 값이 할당되는 과정에서 자동으로 변수의 타입이 결정(타입 추론, Type Inference)
  • 변수에 고정된 타입이 없으며 같은 변수에 여러 타입의 값을 자유롭게 할당할 수 있다.

 

var foo = 'string';
console.log(typeof foo); // string
foo = 1;
console.log(typeof foo); // number

 

단점으로 예상치못한 타입이 변수에 대입 되어 오류가 발생하는 경우도 있는데

타입 스크립트 ts 를 사용하여 해결 할 수 있음.

 

 


 

1. 데이터 타입
데이터 타입(Data Type)은 프로그래밍 언어에서 사용할 수 있는 데이터(숫자, 문자열, 불리언 등)의 종류를 말한다.

모든 데이터는 메모리에 저장하고 참조할 수 있어야 한다.

메모리 공간의 크기와 할당할 수 있는 유효한 값, 2진수 데이터를 어떻게 해석할지에 대한 정보를 제공한다.

데이터 타입은 한정된 메모리 공간을 효율적으로 사용하기 위해서 존재한다.

자바스크립트의 모든 값은 데이터 타입을 갖는다. 

ECMAScript 표준(ECMAScript 2015 (6th Edition), 이하 ES6)은 7개의 데이터 타입을 제공

원시 타입 (primitive data type)

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


객체 타입 (object/reference type)

  • object

 

명확한 의도를 가지고 타입을 구별하여 값을 만들 것이고 자바스크립트 엔진은 타입을 구별하여 값을 취급할 것이다.

자바스크립트에서 제공하는 7개의 데이터 타입은 크게 원시 타입(primitive data type)과 객체 타입(object/reference type)으로 구분할 수 있다.

 


 

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

 

1.1.1 number
C나 Java의 경우, 정수와 실수를 구분하여 int, long, float, double 등과 같은 다양한 숫자 타입이 존재한다. 

하지만 자바스크립트는 독특하게 하나의 숫자 타입만 존재한다.

 

  • 하나의 숫자 타입: 자바스크립트에서는 정수와 실수를 구분하지 않고 모두 부동소수점 형식으로 처리합니다. 이는 다른 언어들에서처럼 정수 타입(int, long 등)이나 다른 부동소수점 형식(float 등)을 별도로 구분하지 않는 것을 의미합니다.
  • 부동소수점 형식: 이 숫자 타입은 모든 수를 실수로 처리합니다. 정수만을 위한 별도의 데이터 타입이나 특별한 integer type이 존재하지 않습니다. 이는 매우 크거나 매우 작은 숫자를 포함하여 소수점 아래 수치를 포함할 수 있음을 의미합니다.

 

모든 수를 실수로 처리하며 정수만을 표현하기 위한 특별한 데이터 타입(integer type)은 없다.

 

 

따라서 정수로 표시되는 수 끼리 나누더라도 실수가 나올 수 있다.

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

 

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

 

var pInf = 10 / 0;  // 양의 무한대
console.log(pInf);  // Infinity

var nInf = 10 / -0; // 음의 무한대
console.log(nInf);  // -Infinity

var nan = 1 * 'string'; // 산술 연산 불가
console.log(nan);       // NaN

 

 

 

요약

  • 모든 수를 실수(float) 로 처리한다. int 타입이 없다.

 


 

1.1.2 string
문자열(String) 타입은 텍스트 데이터를 나타내는데 사용한다. 

문자열은 0개 이상의 16bit 유니코드 문자(UTF-16) 들의 집합으로 대부분의 전세계의 문자를 표현할 수 있다. 

문자열은 작은 따옴표(‘’) 또는 큰 따옴표(“”) 안에 텍스트를 넣어 생성한다. 

가장 일반적인 표기법은 작은 따옴표를 사용하는 것이다.

 

 
var str = "string"; // 큰 따옴표
str = 'string';     // 작은 따옴표
str = `string`;     // 백틱(ES6 템플릿 리터럴)
 

 

C와 같은 언어와는 다르게, 자바스크립트의 문자열은 원시 타입이며 변경 불가능(immutable)하다. 

이것은 한 번 문자열이 생성되면, 그 문자열을 변경할 수 없다는 것을 의미한다. 아래의 코드를 살펴보자.

 

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

 

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

 

이때 문자열 ‘Hello’와 ‘world’는 모두 메모리에 존재하고 있다.

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

 

불변성

한 번 생성된 문자열은 수정할 수 없습니다. 따라서 기존의 문자열을 직접 수정하는 것이 불가능하며, 변경이 필요할 때마다 새로운 문자열이 생성됩니다.

 

문자열 리터럴의 재사용

동일한 문자열 리터럴이 여러 번 사용될 경우, 자바스크립트 엔진은 하나의 문자열 객체를 여러 변수가 공유하게 될 수 있습니다. 예를 들어, var str1 = 'Hello'; var str2 = 'Hello';일 때, 'Hello'라는 문자열 리터럴은 메모리에서 단 한 번만 저장될 수 있습니다.

 

 

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

 
var str = 'string';
// 문자열은 유사배열이다.
for (var i = 0; i < str.length; i++) {
  console.log(str[i]);
}

// 문자열을 변경할 수 없다.
str[0] = 'S';
console.log(str); // string
 

 

 

 

요약

  • 문자열은 유사배열로 인덱스를 통해 접근할 수 있다.
  • 문자열은 수정할 수 없다.
  • 변경이 필요할 시 새로운 문자열을 생성하여 재할당한다.
  • 동일한 문자열 리터럴에 대해서 하나의 문자열 객체를 여러 변수가 공유 한다.

 

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

 

var foo = true;
var bar = false;

// typeof 연산자는 타입을 나타내는 문자열을 반환한다.
console.log(typeof foo); // boolean
console.log(typeof bar); // boolean

 

불리언 타입의 값은 참과 거짓으로 구분되는 조건에 의해 프로그램의 흐름을 제어하는 조건문에서 자주 사용한다.
비어있는 문자열과 null, undefined, 숫자 0은 false로 간주된다.

 


 

1.1.4 undefined
undefined 타입의 값은 undefined가 유일하다. 

선언 이후 값을 할당하지 않은 변수는 undefined 값을 가진다. 

선언은 되었지만 값을 할당하지 않은 변수에 접근하거나 존재하지 않는 객체 프로퍼티에 접근할 경우 undefined가 반환된다.

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

 

____ -> 변수 선언 -> indefined -> 값 할당 -> 해당 값

 

개발자가 의도적으로 할당한 값이 아니라 자바스크립트 엔진에 의해 초기화된 값이다

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


 

1.1.5 null
null 타입의 값은 null이 유일하다. 

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

프로그래밍 언어에서 null은 의도적으로 변수에 값이 없다는 것을 명시할 때 사용한다. 

이는 변수가 기억하는 메모리 어드레스의 참조 정보를 제거하는 것을 의미하며 

자바스크립트 엔진은 누구도 참조하지 않는 메모리 영역에 대해 가비지 콜렉션을 수행할 것이다.

 

 
 
var foo = 'Lee';
foo = null;  // 참조 정보가 제거됨
console.log(foo) // null
console.log(typeof(foo)) // object
console.log(typeof(foo) === null) // false
console.log(foo === null) // true
 

 

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

타입을 나타내는 문자열을 반환하는 typeof 연산자로 null 값을 연산해 보면 null이 아닌 object가 나온다.

이는 자바스크립트의 설계상의 오류이다.

 

따라서 null 타입을 확인할 때 typeof 연산자를 사용하면 안되고 일치 연산자(===)를 사용하여야 한다.

 

 

요약

  • null 은 변수에 값이 없다는 것을 명시한다.
  • 함수가 유효한 값을 반환할 수 없는 경우에도 사용된다.
  • null 타입 확인은 typeof 가 아닌 === 를 사용해야 된다.

 


 

1.1.6 symbol
심볼(symbol)은 ES6에서 새롭게 추가된 7번째 타입으로 변경 불가능한 원시 타입의 값이다. 

심볼은 주로 이름의 충돌 위험이 없는 유일한 객체의 프로퍼티 키(property key)를 만들기 위해 사용한다. 

심볼은 Symbol 함수를 호출해 생성한다. 이때 생성된 심볼 값은 다른 심볼 값들과 다른 유일한 심볼 값이다.

 

// 심볼 key는 이름의 충돌 위험이 없는 유일한 객체의 프로퍼티 키
var key = Symbol('key');
console.log(typeof key); // symbol

var obj = {};
obj[key] = 'value';
console.log(obj[key]); // value

 

유일성

Symbol은 유일무이한 값을 가집니다. 즉, 동일한 인수로 여러 번 호출해도 항상 새로운 Symbol 값을 생성합니다.

 
let symbol1 = Symbol();
let symbol2 = Symbol();
console.log(symbol1 === symbol2); // false - 각각의 Symbol은 서로 다릅니다.
 

 

 

설명(Description)

Symbol을 생성할 때 선택적으로 문자열을 전달하여 설명을 추가할 수 있습니다.

이 설명은 Symbol을 디버깅할 때 유용합니다.

 
let symbol = Symbol('mySymbol');
console.log(symbol.description); // 'mySymbol' - Symbol의 설명을 가져옵니다.

 

 

객체 프로퍼티 키

Symbol은 주로 객체의 프로퍼티 키로 사용됩니다.

Symbol을 사용하면 프로퍼티가 우연히 충돌하지 않고 고유한 것임을 보장할 수 있습니다.

const obj = {};
const sym = Symbol('key');
obj[sym] = 'value';
console.log(obj[sym]); // 'value'

 

 

전역 Symbol 레지스트리

자바스크립트는 전역 Symbol 레지스트리(global symbol registry)를 제공하여 동일한 설명을 가진 Symbol이 공유될 수 있도록 합니다. 이를 이용하면 다른 코드에서도 동일한 Symbol을 참조할 수 있습니다.

const globalSym = Symbol.for('globalSymbol');
let localSym = Symbol.for('globalSymbol');
console.log(globalSym === localSym); // true - 동일한 Symbol을 참조합니다.

 

 

내장 Symbol

자바스크립트에는 몇 가지 내장(Symbol.species, Symbol.iterator 등)된 Symbol이 있습니다.

이들은 특정 동작을 수행하기 위해 자바스크립트 엔진 내부에서 사용됩니다.

 

 

요약

Symbol은 주로 객체의 프로퍼티 키로 사용되어야 하며, 유일성을 보장하고 충돌을 방지하기 위한 목적으로 사용됩니다.

 


 

1.2 객체 타입 (Object type, Reference type)
객체는 데이터와 그 데이터에 관련한 동작(절차, 방법, 기능)을 모두 포함할 수 있는 개념적 존재이다. 

  • key-value 의 이름과 값을 가지는 데이터를 의미하는 프로퍼티(property)
  • 동작을 의미하는 메소드(method)

 

자바스크립트는 객체(object) 기반의 스크립트 언어로서 자바스크립트를 이루고 있는 거의 “모든 것”이 객체이다. 

원시 타입(Primitives)을 제외한 나머지 값들(배열, 함수, 정규표현식 등)은 모두 객체이다. 

또한 객체는 pass-by-reference(참조에 의한 전달) 방식으로 전달된다.

 

 


 

2. 변수

 

프로그램에서 사용되는 데이터를 일정 기간 동안 기억하여 필요한 때에 다시 사용하기 위해 데이터에 고유의 이름인 식별자(identifier)를 명시한 것이다.

변수에 명시한 고유한 식별자를 변수명이라 하고 변수로 참조할 수 있는 데이터를 변수값이라 한다.


변수는 var, let, const 키워드를 사용하여 선언하고 할당 연산자를 사용해 값을 할당한다. 

그리고 식별자인 변수명을 사용해 변수에 저장된 값을 참조한다.

 

식별자는 어떤 대상을 유일하게 식별할 수 있는 이름을 말한다. 

식별자에는 변수명, 함수명, 프로퍼티명, 클래스명 등이 있다.

 

  • 데이터는 메모리에 저장되어있다.
  • 식별자는 메모리의 주소를 기억한다. 
  • 따라서 식별자를 통해 메모리에 저장된 값을 참조할 수 있다.

 

 

2.1 변수의 선언

  • 일정 기간 유지할 필요가 있는 값에 사용한다.
  • 값의 의미가 명확해져서 코드의 가독성이 좋아진다.
  • 변수의 존재 목적을 쉽게 이해할 수 있도록 의미있는 변수명을 지정

 

명명 규칙


반드시 영문자(특수문자 제외), underscore ( _ ), 또는 달러 기호($)로 시작하여야 한다. 

이어지는 문자에는 숫자(0~9)도 사용할 수 있다.
자바스크립트는 대/소문자를 구별하므로 사용할 수 있는 문자는 “A” ~ “Z” (대문자)와 “a” ~ “z” (소문자)이다.

 

변수를 선언할 때는 var 키워드를 사용한다. 

등호(=, equal sign)는 변수에 값을 할당하는 할당 연산자이다.

값을 할당하지 않은 변수 즉 선언만 되어 있는 변수는 undefined로 초기값을 갖는다. 

선언하지 않은 변수에 접근하면 ReferenceError가 발생한다.

 

 
var x;
console.log(x); // undefined
console.log(y); // ReferenceError
 

 

 

2.1 변수의 중복 선언
var 키워드로 선언한 변수는 중복 선언이 가능하다.

변수의 중복 선언은 문법적으로 허용되지만 사용하지 않는 것이 좋다.

 

 

2.2 동적 타이핑 (Dynamic Typing)
자바스크립트는 동적 타입(dynamic/weak type) 언어이다. 

변수의 타입 지정(Type annotation)없이 값이 할당되는 과정에서 값의 타입에 의해 자동으로 타입이 결정(Type Inference)

따라서 같은 변수에 여러 타입의 값을 할당할 수 있다. 이를 동적 타이핑(Dynamic Typing)이라 한다.

 

 

2.3 변수 호이스팅(Variable Hoisting)

 

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

 

var 키워드를 사용하여 선언한 변수는 중복 선언이 가능하기 때문에 위의 코드는 문법적으로 문제가 없다.

①에서 변수 foo는 아직 선언되지 않았으므로 ReferenceError: foo is not defined가 발생할 것을 기대했겠지만 콘솔에는 undefined가 출력된다.

이것은 다른 C-family 언어와는 차별되는 자바스크립트의 특징으로 모든 선언문은 호이스팅(Hoisting)되기 때문이다.


호이스팅

var 선언문이나 function 선언문 등 모든 선언문이 해당 Scope의 선두로 옮겨진 것처럼 동작하는 특성을 말한다.

즉, 자바스크립트는 모든 선언문(var, let, const, function, function*, class)이 선언되기 이전에 참조 가능하다.

 

보이지않는 var foo ; 가 실행된다고 볼 수 있음.

 


변수 생성 단계

 

1. 선언 단계(Declaration phase)

  • 변수 객체(Variable Object)에 변수를 등록한다.
  • 이 변수 객체는 스코프가 참조하는 대상이 된다.

 

2. 초기화 단계(Initialization phase)

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

 

3. 할당 단계(Assignment phase)

  • undefined로 초기화된 변수에 실제값을 할당한다.


var 키워드로 선언된 변수는 선언 단계와 초기화 단계가 한번에 이루어진다. 

스코프에 변수가 등록되고 변수는 메모리에 공간을 확보한 후 undefined로 초기화된다. 

따라서 변수 선언문 이전에 변수에 접근하여도 Variable Object에 변수가 존재하기 때문에 에러가 발생하지 않는다. 

다만 undefined를 반환한다. 이러한 현상을 변수 호이스팅(Variable Hoisting)이라한다.

이후 변수 할당문에 도달하면 비로소 값의 할당이 이루어진다.

 

 

 

 

①이 실행되기 이전에 var foo = 123;이 호이스팅되어 ①구문 앞에 var foo;가 옮겨진다.

실제로 변수 선언이 코드 레벨로 옮겨진 것은 아니고 변수 객체(Variable object)에 등록되고 undefined로 초기화된 것이다.

 

 

자바스크립트의 변수는 다른 C-family와는 달리 블록 레벨 스코프(block-level scope)를 가지지 않고 함수 레벨 스코프(function-level scope)를 갖는다. 따라서 코드 블록 내의 변수 foo는 전역변수이므로 전역에 선언된 변수 foo에 할당된 값을 재할당하기 때문에 ③의 결과는 456이 된다.

 

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

블록 레벨 스코프가 가능하다면 ③의 결과는 123이 된다. 

 


 

2.4 var 키워드로 선언된 변수의 문제점
ES5에서 변수를 선언할 수 있는 유일한 방법은 var 키워드를 사용하는 것이다. var 키워드로 선언된 변수는 아래와 같은 특징을 갖는다. 이는 다른 C-family 언어와는 차별되는 특징(설계상 오류)으로 주의를 기울이지 않으면 심각한 문제를 발생시킨다.

 


함수 레벨 스코프(Function-level scope)

  • 전역 변수의 남발
  • for loop 초기화식에서 사용한 변수를 for loop 외부 또는 전역에서 참조할 수 있다.


var 키워드 생략 허용

  • 의도하지 않은 변수의 전역화


중복 선언 허용

  • 의도하지 않은 변수값 변경


변수 호이스팅

  • 변수를 선언하기 전에 참조가 가능하다.

 

전역 변수는 간단한 애플리케이션의 경우, 사용이 편리한 면이 있지만 불가피한 상황을 제외하고 사용을 억제해야 한다. 

전역 변수는 유효 범위(scope)가 넓어서 어디에서 어떻게 사용될 지 파악하기 힘들다. 

이는 의도치 않은 변수의 변경이 발생할 수 있는 가능성이 증가한다. 

또한 여러 함수와 상호 의존하는 등 부수 효과(side effect)가 있을 수 있어서 복잡성이 증가한다.

 

 

변수의 유효 범위(scope)는 좁을수록 좋다.

 


ES6는 이러한 var의 단점을 보완하기 위해 let과 const 키워드를 도입하였다.

 

 

 

https://chatgpt.com/