[ 살펴보기 ] Javascript - Data types

[ 살펴보기 ] Javascript - Data types

·

8 min read

Javascirpt에서 data type은 크게 primary, reference type으로 분류할 수 있다. number, bigint, string, boolean, undefiend, null, symbol type은 모두 primitive type에 해당하며 그 외에 object, array, Date등은 모두 reference type으로 분류된다.

number ( primitive type )

int, long, float 등과 같은 다양한 number type을 가진 Java나 C#과 같은 langauge와는 달리 Javascript의 number type은 별도의 구분 없이 하나의 type으로 사용한다. 즉, 아래는 모두 같은 number type이다

const test1 = 100;
const test2 = 25.2;
const test3 = -100;

Javascript에서 number는 실수( real number )로 처리되기 때문에 아래의 두 수는 true로 해석된다.

console.log(5 === 5.0);

Javascript에서 무한대를 나타내는 Infinity와 산술이 불가능한 Not a Number를 나타내는 NaN type 역시 number type으로 취급된다.

  console.log(typeof Infinity === "number"); // true
  console.log(typeof -Infinity === "number"); // true 
  console.log(typeof NaN === "number"); // true

BigInt ( primitive type )

Javascript의 number type이 정확도를 보장할 수 있는 max value는 9007199254740991다.

console.log(Number.MAX_SAFE_INTEGER) // 9007199254740991

Number.MAX_SAFE_INTEGER 범위를 벗어나는 number type value는 정확도를 보장하지 못하기에 다루어야 하는 값이 MAX_SAFE_INTEGER 값을 벗어나는 큰 value일 경우 BigInt type을 사용한다. BigInt type value는 숫자 마지막에 character n을 추가하거나 BigInt function을 통해 생성한다.

const test1 = 123n;
const test2 = BigInt(123);

BigInt type 역시 number type과 마찬가지로 더하거나 빼는 등의 operation을 수행할 수 있다.

const test = 123n + 123n;
console.log(test) // 246n

주의할 점은 BigInt와 number type은 다른 타입이기에 다음과 같이 서로 다른 타입을 기준으로 math operation을 수행할 수는 없다.

const test = 123n + 123;
console.log(test) // Uncaught TypeError: Cannot mix BigInt and other types

서로 다른 type을 math operation을 통해 계산하고자 한다면 둘 중 하나는 다른 type으로 변환하고 operation을 수행해야 한다.

const test1 = 123n + BigInt(123);
const test2 = Number(123n) + 123;

더하기 빼기와 같은 operation과는 다르게 값의 크기를 비교하는 operation은 BigInt와 number type을 함께 사용해도 무방하다.

console.log(3n < 1) // false
console.log(3n == 3) // true
console.log(3n === 3) // false

Boolean을 check하는 operation에서 BigInt 0n은 number type 0과 같이 falsy value로 취급된다.

if(0n) { // 0n는 falsy value로 취급된다.
  console.log(' ::: 0n is truthy ::: ')
}else{
  console.log(' ::: 0n is falsy ::: ')
}

BigInt type 사용시 주의할 점은 BigInt는 interger value에 사용할 수 있으며 소수점을 가진 숫자에는 사용할 수 없다.

console.log(1233n) // 1233n
console.log(-1233n) // -1233n
console.log(-123.3n) // SyntaxError: Invalid or unexpected token

string ( primitive type )

Javascriprt에서 string type을 표현할 때 작은따옴표를 사용하든 큰따옴표를 사용하든 상관없이 string type으로 표현된다. 백틱( `` )을 사용해도 마찬가지다.

const test1 = "test1";
const test2 = 'test2';
const test3 = `test3`;

template literal내에 모든 value는 string으로 처리되므로 주의하자.

const test1 = `test1-${1+1}`; // test1-2
const test2 = `test2-${true}` // test2-true

boolean, undefined, null ( primitive type )

Javascript의 boolean type은 true, false를 사용할 수 있고 undefined type은 undefined, null type은 null을 사용한다.

console.log(typeof undefined === "undefined"); // true
console.log(typeof true === "boolean"); // true
console.log(typeof false === "boolean"); // true

특정 data가 null type인지 검사할 때 주의해야 할 사항이 있다.

console.log(typeof null) // object

다음과 같이 null의 type을 체크해보면 object로 나오기 때문에 null type check는 typeof keyword를 통해 수행하지 않는다. 이는 javascirpt language 설계 상의 문제이며 특정 data의 null type check는 다음과 같이 수행한다.

const randomValue = null;
if (randomValue === null) {
  console.log(" randomValue is null");
}

추가로 개발자가 명시적으로 특정한 variable에 값이 없다는 것을 표현하기 위해선 undefiend 보다는 null을 사용하는 것이 좋다. var 또는 let keyword를 통해 선언한 variable에 특정 값을 할당 하지 않으면 javasciprt engine이 해당 variable을 undefined으로 초기화 하므로 개발자가 명시적으로 variable 값이 없다는 것을 표현할 때는 undefined 보다 null을 사용하자.

Symbol ( primitive type )

ES6에서 추가된 data type이며 다른 값과 중복이 발생하지 않는 유일한 값이다. Symbol 함수를 통해 생성한다.

const test = Symbol("test");
console.log(typeof test); // symbol

위의 예제와 같이 Symbol 함수에 string value를 전달할 수 있지만 전달하는 string value가 생성되는 symbol value에 영향을 미치지는 않는다. 즉, Symbol 함수에 전달하는 string value는 생성하는 Symbol에 대한 description 역할을 할 뿐이다.

const test = Symbol("test");
const test2 = Symbol("test");

console.log(test === test2); // false
console.log(test.description); // test

주의할 점은 symbol은 다음과 같이 암묵적으로 string 또는 number type으로 변환될 수 없다. 아래 code는 template string을 통해 test라는 Symbol type data를 암묵적으로 string type으로 변환하려고 하고 있으며 아래 code를 실행 시키면 에러가 발생한다.

const test = Symbol("test");
const test2 = Symbol("test");
console.log(`${test}`); // Uncaught TypeError: Cannot convert a Symbol value to a string

이렇게 생성한 symbol type은 object의 property key로도 사용할 수 있다. 예를 들어 아래 예제에서 testObj의 property key를 모두 symbol type으로 지정하였기에 다른 property key와 중복으로 인한 충돌이 발생하지 않는 유일한 property key가 된다.

const test = Symbol("test");
const test2 = Symbol("test");
const testObj = {
  [test]: "A",
  [test2]: "B",
};
console.log(testObj[test]); // A
console.log(testObj[test2]); // B

symbol type을 사용할 때 주의할 점은 위와 같이 property key를 symbol type으로 사용하면 Object.keys나 for … in statement에서 object의 property가 조회되지 않는다.

const test = Symbol("test");
const test2 = Symbol("test");
const testObj = {
  age: 20,
  [test]: "A",
  [test2]: "B",
};

const test3 = Object.keys(testObj);
console.log(test3); // ['age']

object propery 중 symbol type을 key로 사용하는 property를 조회하려면 다음과 같이 Object의 getOwnPropertiesSymbols method를 사용한다.

const test = Symbol("test");
const test2 = Symbol("test");
const testObj = {
  age: 20,
  [test]: "A",
  [test2]: "B",
};

const test3 = Object.getOwnPropertySymbols(testObj);
console.log(test3); // [Symbol(test), Symbol(test)]
console.log(testObj[test3[0]]); // A

Reference types

위에서 살펴본 primitive type을 제외한 data type은 모두 reference type으로 분류된다. 그리고 reference type의 거의 모든 data는 내부적으로 object type으로 해석되어 처리된다.

const testObj = { name: "test" }; // object
const testArr = [1, 2]; // array
const testDate = new Date(); // date

console.log(typeof testObj); // object
console.log(typeof testArr); // object
console.log(typeof testDate); // object

Object

javascript에서 객체를 생성하는 방법은 여러가지 존재하지만 일반적으로 다음과 같이 객체 literal 형식을 통해 생성한다.

const testObj = {
    name:"test"
}

const testObj2 = {
    age:20,
    nestedObj:testObj
}

const testObj3 = {
  address: "test address",
  getAddress: function () {
    return this.address;
  },
};

Array

javascript에서 배열은 다음과 같이 array literal을 통해 생성하는 것이 일반적이다.

const testArr = ["cat","dog","bird"];

const testDetailArr = [
    {name:"cat"},
    {name:"dog"},
    {name:"bird"}
]

또한 array가 가지고 있는 각각의 element들은 array안에 존재하는 위치에 따른 index를 가진다. 그리고 index를 통해 array element 중 특정 element에 접근할 수 있다. ( index는 0부터 시작한다 )

console.log(testArr[0]); // cat
console.log(testDetailArr[1]); // {name:"dog"}

주의할 점은 Javascript에서 array는 array의 특정을 따라 구현된 특별한 유형의 object다. Object의 getOwnPropertyDescriptors method를 통해 testDetailArr array를 확인해보면 다음과 같이 array의 index값이 내부적으로 object의 property key로 사용되고 있음을 확인할 수 있다.

 console.log(Object.getOwnPropertyDescriptors(testDetailArr));

// result
{
    "0": {
        "value": {
            "name": "cat"
        },
        "writable": true,
        "enumerable": true,
        "configurable": true
    },
    "1": {
        "value": {
            "name": "dog"
        },
        "writable": true,
        "enumerable": true,
        "configurable": true
    },
    "2": {
        "value": {
            "name": "bird"
        },
        "writable": true,
        "enumerable": true,
        "configurable": true
    },
    "length": {
        "value": 3,
        "writable": true,
        "enumerable": false,
        "configurable": false
    }
}

Date

javascript에서 date object는 Date 생성자 함수를 통해 생성한다. 아래의 예제처럼 Date 생성자 함수를 실행하면 javascript가 실행되는 system의 현재 시간을 return한다.

const today = new Date();

만약 특정한 날짜, 시간 정보를 가진 date object를 생성하고 싶다면 다음과 같이 date 정보를 Date 생성자 함수에 전달하여 생성할 수 있다.

const someDay = new Date("2025-01-01 13:00:00");

여기서 주의할 점은 Date 생성자 함수에 전달하는 string은 Date.parse에 의해 정상적으로 parse될 수 있는 형태여야 한다. 즉, 다음과 같은 형태의 string을 전달하면 정상적으로 date object가 생성되지 않는다.


const dateString = "2025_01_01 13:00:00"

const someDay = new Date(dateString); // Invalid Date

console.log(Date.parse(dateString)) // NaN

문자열 뿐만 아니라 다음과 같이 연, 월, 일, 시 등과 같은 시간 정보를 숫자로 전달해서 date object를 생성할 수도 있다. 여기서 주의할 점은 월을 나타내는 숫자는 0부터 시작한다. 즉, 0이 1월을 나타낸다.

const today = new Date(2025,0,1,13,0,0);

Set

set object는 array와 유사하지만 유일한 값의 집합을 위해 사용되는 object다. array는 중복된 값을 포함할 수 있지만 set object는 동일한 값을 중복해서 저장하지 않으며 array와는 달리 각 element가 순서를 가지지 않기에 index로 접근할 수 없다.

const testSet = new Set(['a','b','c']); // Set(3) {'a', 'b', 'c'}

아래의 예제와 같이 중복된 값은 저장되지 않는다.

const testSet = new Set(['a','a','b','c']); // Set(3) {'a', 'b', 'c'}

이러한 Set의 특성을 이용해 array의 중복 data를 쉽게 제외할 수 있다.

const testArr = ['a', 'a', 'b', 'b', 'c', 'c']

const testSet = [ ...new Set(testArr)]; // ['a', 'b', 'c']

Set object는 array와 달리 element의 갯수를 파악할 때 length가 아닌 size property를 사용한다. 아래 예제에서 중복 데이터는 저장되지 않으므로 Set의 size는 3이다.

const testSet = new Set(['a','a','b','c']);
console.log(testSet.size) // 3

Map

Map object는 Set object와는 달리 각 element가 key/value pair로 이루어 진다.

const testMap = new Map([['a', 'a value'], ['b', 'b value']]);
// Map(2) {'a' => 'a value', 'b' => 'b value'}

Map object는 중복 각 element의 value는 중복되는 value를 허용하지만 중복되는 key는 허용하지 않기에 중복되는 key가 있으면 마지막에 추가된 key/value pair element가 이전의 key/value pair element를 override한다.

const testMap = new Map([['a', 'a value'], ['b', 'b value'], ['a', 'aa value']]);
// Map(2) {'a' => 'aa value', 'b' => 'b value'}

Map object 역시 element의 개수를 구할 때 length가 아닌 size property를 사용한다. 아래 예제에서 중복되는 key를 가진 element가 존재하므로 testMap object의 size는 2다.

const testMap = new Map([['a', 'a value'], ['b', 'b value'], ['a', 'aa value']]);
console.log(testMap.size) // 2

Falsy value

javascript에서 false로 취급되는 falsy data는 false, undefined, null 외에도 존재하기 때문에 주의가 필요하다. javascript에서 falsy로 취급되는 data는 다음과 같다.

  • null

  • undefined

  • false

  • NaN

  • 0 ( number type )

  • ““ ( 빈 문자열 )

  • 0n ( Bigint zero )

  • document.all ( the only falsy object in javascript )

if(null) {
  console.log(' ::: truthy ::: ')
}else {
  console.log(' ::: falsy ::: ')
}

if(undefined) {
  console.log(' ::: truthy ::: ')
}else {
  console.log(' ::: falsy ::: ')
}

if(NaN) {
  console.log(' ::: truthy ::: ')
}else {
  console.log(' ::: falsy ::: ')
}

if(0) {
  console.log(' ::: truthy ::: ')
}else {
  console.log(' ::: falsy ::: ')
}

if("") {
  console.log(' ::: truthy ::: ')
}else {
  console.log(' ::: falsy ::: ')
}

if(document.all) {
  console.log(' ::: truthy ::: ')
}else {
  console.log(' ::: falsy ::: ')
}