프론트 공부/JavaScript와 모던 JS

JavaScript의 자료형

홍구리당당 2023. 10. 17. 16:45

0. 오늘의 배울 것.

프로그래밍의 기초는 자료형!!

어느 언어를 배우든간에 자료형을 공부하는 것은 기초 중의 기초이다. 개인적으론 js의 자료형은 특이한 점이 많았는데, 이번 기회에 제대로 알아보자.

1. 숫자형

숫자형을 계산해보자. 파이썬이랑 비슷한 느낌이다. 신기한 건 정수, 실수형으로 나뉘지 않고 2나 2.0이나 둘 다 number 형이라고 나오는 것이다!! 그래서 나눗셈을 하면 무조건 실수가 출력된다.

만약 몫 나눗셈을 하고 싶다면, Math.floor 메소드를 활용하자.

//몫 나눗셈.
console.log(Math.floor(7/3));

// 거듭제곱.
console.log(2 ** 3);

// 나머지 연산.
console.log(7 % 3);

// 나눗셈. 소수형으로 출력된다.
console.log(5 / 2);

숫자 표기하기.

java나 c 언어 같은 녀석들은, int 형의 범위가 한정되어있다. int 타입 변수에 4바이트만 할당하기 때문이다. 그런데 파이썬이나 js는 굉장히 큰 범위의 수까지 표현할 수가 있다!! 때문에 큰 숫자를 표현할 때도 여러 방법이 있다.

  1. 예를 들어 10억을 표현하려면?
    // 1 뒤에 0이 9개 붙는다.
    let milli = 1e9;
  2. 10진법이 아닌 수 표현. (사실 실무에선 10진법 말고는 웬만해서 잘 쓰진 않을테지만, 가끔 백준 문제에서 숫자를 n진법으로 바꾸라는 문제가 나온다.)
    // 16진법은 0x 붙이기
    let hex1 = 0xff;
    let hex2 = 0xff;
    

// 8진법은 0o 붙이기
let octal = 0o377;

// 2진법은 0b 붙이기
let binary = 0b1101;



### 숫자형 메소드.

Number 도 일종의 객체이기에, 메소드가 있다!! 자주 쓰이는 메소드 몇 개를 추려보았다.

1.  **toFixed()** 는 소수점을 n번째 자리까지 살리고 반올림하는 것. 주의할 건 **number.toFixed() 해서 나온 값은 string이라 덧셈연산할 경우엔 형변환을 해야 한다!!**

```js
//0.1592에서 0.159가 된다.
console.log(myNumber.toFixed(3));

하나 그냥 팁!! string을 number로 바꿀 때 number 함수를 써도 되지만 그냥 + 기호만 붙여도 형변환 됨.

// 341이 문자열 말고 숫자로 출력된다.
console.log(+"341");
  1. toString() 은 n진수로 수를 바꿔준다. toString 메소드에 인자를 주지 않으면 그냥 숫자가 10진법 그대로 문자열로 변환되지만, 인자로 n 값을 주면 숫자가 n진법으로 변환된다. 이 때 toString() 메소드가 반환한 값은 당연히 문자열이다!!
// ff 출력됨.
let number = 255;
console.log(number.toString(16));

// 아예 숫자에 toString 적용하려면 숫자에 괄호 치거나 .을 두 개 써서 할 수도 있다!!
console.log((255).toString(16));
console.log((255).toString(16));

Math 객체

Math 객체는 js 말고 파이썬이나 다른 언어에도 있는 패키지라, 대부분에게 익숙할 것이다. js에서도 Math 객체를 통해 웬만한 연산은 할 수 있다!

// 1.  절댓값 리턴하기.
console.log(Math.abs(-10));

// 2.  최댓값 최솟값 리턴하기.
console.log(Math.max(2, -1, 4, 5, 0));
console.log(Math.min(2, -1, 4, 5, 0));

// 3.  거듭제곱 리턴하기. 2의 3승이므로 8 출력.
console.log(Math.pow(2, 3));

// 4.  제곱근 리턴하기
console.log(Math.sqrt(25));

// 5.  반올림 리턴하기
// toFixed는 string 반환, round는 number 반환.
console.log(Math.round(2.462));

// 6.  버림과 올림 리턴하기
// 버림. js에는 몫 연산이 없기때문에 floor 메소드를 통해 몫연산을 한다.
console.log(Math.floor(2.5));
// 올림
console.log(Math.ceil(2.5));

// 7.  난수 리턴하기 (랜덤)
// 0~1 사이 값이 랜덤 리턴.
console.log(Math.random());

 

2. 문자열

따옴표, 쌍따옴표 안에 들어있는 문자들의 나열.

신기하게도 쌍따옴표 내부에선 \ 없이도 따옴표 하나는 그냥 문자로 포함된다. 이런 점에선 굉장히 유연한 언어라는 게 느껴진다.

console.log("I'm Iron man");

그치만 여러 개의 따옴표와 쌍따옴표가 섞여 있으면 \를 써야 하니, 그냥 \를 쓰는 걸 습관으로 들이자.

그런데 js에서는 백틱 표시도 문자열로 취급한다! 백틱을 통해 문자열 포맷팅도 가능해서, 필자는 백틱 기호를 제일 많이 사용한다.

console.log(`I'm'''' Iron man`);
// 이 백틱 ` 표시로 감싸면 역슬래시 없이 따옴표 남발도 가능!

string 형은 특히 배열과 비슷한 구석이 많다. 그렇지만 typeof로 비교하면 string형은 string으로, 배열은 object로 분명히 구분되어 나타난다.

string형과 배열의 비슷한 점.

// 1. 문자열 길이 리턴할 때 length 쓴다.
console.log(str.length);

// 2. 요소 찾을 때 대괄호 표기법이나 메소드를 사용. 즉, 인덱스 접근이 가능하다.
console.log(str[3]);
console.log(str.charAt(3));

// 3. 요소 위치 찾을 때 indexOf 사용.
console.log(str.indexOf("i"));
console.log(str.lastIndexOf("i"));

// 신기한 점. indexOf로 문자열도 찾을 수 있다. 이 경우 a의 인덱스를 리턴함.
console.log(str.indexOf("abc"));

문자열과 배열의 차이점.

주의하자!! 배열과 문자열은 엄연히 다르다 왜냐면 배열은 원소를 바꿀 수 있는 mutable, 문자열은 바꿀 수 없는 immutable 자료형이기 때문이다.

// 모두 false로 출력됨.
let myString = "Codeit";
let myArray = ["C", "o", "d", "e", "i", "t"];

console.log(myString === myArray);
console.log(myString == myArray);

따라서 문자열에는 splice 같은 메소드는 사용할 수 없다!!

이 밖에도 문자열에만 있고, 배열에 쓸 수 없는 메소드들은 아래와 같다.

// 1.  대문자화 소문자화.
console.log(str.toUpperCase());
console.log(str.toUpperCase());

// 2.  문자열 맨 양 끝의 공백을 삭제. (가운데 공백은 살림.)
console.log(str.trim());

// 3.  부분 문자열 가져오기
// 문자열 0, 1번 가져옴.
console.log(str.slice(0, 2));
// 문자열 1번부터 끝까지 가져옴
console.log(str.slice(1));
// 문자열 모두 가져옴.
console.log(str.slice());

이건 정말 내가 많이 헷갈려하는 것이다.

문자열을 자르고 고치는 메소드는 substring

그리고 배열을 자르고 고치는 메소드는 splice, slice 이다.

splice, slice 둘 다 배열 메소드이고, string에는 쓸 수 없다!! 두 메소드의 차이에 대해서는 배열 편에서 더 알아보자.

(항상 문제 풀 때마다 파이썬 습관이 남아있어서 str[:] 이나 str.slice()... 를 쓰고 에러 폭탄을 맞는다.. 헷갈리지 말고 잘 기억하자.)

 

3. 불 대수와 불린형

일상적인 논리를 수학적으로 표현한 것을 불 대수라고 한다.

  • 불 대수의 값: true, false
  • 불 대수 연산: AND, OR, NOT

그렇다면 불린형은 뭘까?

js에서 참과 거짓을 표현할 때 나타내는 자료형 이다!! 불린형에는 true, false 두 가지 값만 있다.

js에서의 불대수 연산자나 일치불일치 연산은 파이썬과 대개 비슷하지만 js에만 있는 연산자가 하나 더 있다. 바로 =을 3개 연달아서 쓰는, strict equality operator 이다. 그리고 ==는 loose equality operator 라 불린다!

등호 중 == 와 === 둘 다 쓸 수 있다.

  • == 는 값만 비교하고
  • === 는 데이터 타입까지 비교한다.
// 아래 두 문장은 참.
console.log(5 == "5");
console.log(5 === 5);

// 이것은 거짓!
console.log(5==="5");

// 이것도 참이다.
console.log(undefined == null);

// 근데 이건 거짓!!
console.log(undefined === null);

신기하게도 js에서 undefined와 null은 같은 값이지만 타입이 다른 것으로 인식된다.

 

4. null과 undefined

자료형에는 숫자형, 문자형, 불형 뿐만 아니라 null 형, undefined 형이 있다.

  • null : 의도적으로 표현할 때 사용하는 값. 값을 안 넣을 때 null로 선언한다.
  • undefined : 값이 없다는 것을 확인하는 값. 기본적으로 선언된 변수는 딱히 값을 넣어주지 않으면 undefined 값을 가진다. 즉, 지정된 값이 없다는 것을 확인할 수 있다!!

신기하게도, null과 undefined는 다른 자료형이지만 데이터 값 자체는 같다고 인식된다.

// 얘는 참인데
console.log(null == undefined);

// 얘는 또 거짓으로 나옴.
console.log(null === undefined);

즉 변수 선언해서 의도적으로 let value = undefined; 하고 값을 넣어줄 수는 있지만, 그렇게 쓰면 의미가 퇴색되므로 null을 써주자.

( NaN : 이 건 null, undefined와 다른 개념이다. NaN은 number형 자료형 값으로, 숫자가 아닌데 숫자로 형변환하려 할 경우 나타난다.)

 

5. 형 변환

Type Conversion 이라고도 한다.

Number, String, Boolean 함수를 써서 형변환을 한다!! (가끔 파이썬이랑 헷갈려서 js에서 int 함수를 쓰고 파이썬에선 number 함수를 쓸 때가 있다... --;; 헷갈리지 않게 주의하자.)

conlone.log(Number("10") + Number("5"));
conlone.log(String(10) + String(5));

그런데 "hello" 같이 숫자로 바꿀 수 없는 문자열을 숫자로 바꾸려면 NaN 값이 리턴된다. 근데 이 NaN을 typeof 로 형을 체크하면 숫자형으로 나오긴 한다!! 즉, js에서 number형 자료형에 들어갈 수 있는 값은 정수와 실수 뿐만 아니라 NaN 값도 있다는 것이다.

(이 말고도, 숫자형으로 들어가는 값 중에는 infinity, -infinity 등이 있다. 이건 js가 표현할 수 있는 범위를 넘어서는 숫자를 할당할 때 나타나는 자료형이다. 근데 js가 표현할 수 있는 값의 범위는 -1경~1경 정도로 매우 크다...)

//  NaN 출력된다.
conlone.log(Number("hello"));
// Number 출력된다.
conlone.log(typeof Number("hello"));

Js에선 자동으로 형변환을 하기도 해주기도 하는데, 예를 들어 '4' - true 하면 3이 출력된다.
A 연산자(+, -, / ...+ B 문장에서 A나 B 둘 중 적어도 하나가 숫자라면 나머지 하나도 형변환이 되면서 숫자처럼 연산된다.

단, 연산자가 + 일 경우 숫자형의 덧셈이 아니라 문자열의 덧셈으로 계산이 된다!!

이처럼 자동 형변환이 일어나는 경우는 불규칙하고 예상하기 어려우므로, 가시적으로 형변환 메소드를 쓰는 것이 좋다.

// 일반적으로 산술연산자는 데이터를 자동으로 숫자로 형변환해준다. 단, 덧셈은 문자열 연결 기능이 우선 나타난다!!

// 이 두개는 잘 출력됨.
console.log(4 + "2");
console.log(4 + true);
// 얘는 NaN 출력.
console.log(4 % "two");

// 비교할 수 없는 형에서도 false 출력함.
console.log("two" >= 1);

정리하자면!! 만약 연산에 문자와 숫자가 섞여있을 때 자동 형변환이 일어나는 경우

  1. 산술 연산자: + 에서는 문자열 형이 있으면 둘 다 문자 취급 / 나머지는 숫자 취급.
  2. 관계 비교 연산자: 다 숫자로 형변환되기 때문에 그냥 글자는 NaN 취급된다.
  3. 같음 비교 연산자: ==에서는 자동 형변환이 일어나고, ===에선 자동 형변환 안 일어남!

6. 기본형과 참조형

  • 기본형: Number, string, undefined, null, boolean
  • 참조형: object 배열

참조형이란 변수에 값 그자체가 아니라 값을 가리키는 주소의 값을 담는 자료형이다.

let x ={...};
let y = x;

위의 코드에서 x는 참조형 변수기 때문에 object를 가리키는 주소값을 담고 있다 >> 즉, y에게도 object를 가리키는 주소가 할당되므로 x에서 프로퍼티를 수정하면 y에도 반영된다.

그렇다면 참조형 변수를 주소가 아니라 값만 복사하려면 어떻게 해야 할까?

// 배열 복사하기
let number11 = [1, 2, 3];
let number2 = number1.slice();
// 객체 복사하기
// 이렇게 Object의 메소드를 사용하면 된다.
let obj1 = { ... };
let obj2 = Object.assign({}, obj1);

// for in 문을 사용해서 객체를 복사할 수도 있다.
// 이 코드로 객체를 복사하는 함수를 직접 만들 수도 있다.
let obj3 = {}
for (let key in obj1){
    obj3[key] = obj1[key];
}

이렇게 데이터 자체를 복사하여 복사된 객체가 원본과는 독립된 메모리를 가지는 것을 deep copy, 복사된 객체에 값만 복사되어 주소를 공유하는 것을 shallow copy라 한다. (이 부분은 기술면접 단골 질문이라 하니, 꼭 잘 알아두자.)

객체 안의 객체, 객체 안의 배열이 포함된 경우 for 문으로 객체를 깊은 복사 하려 할 경우 실패할 수도 있다. 때문에 중첩 참조형일 경우는 다른 식으로 접근해야 한다.

참고로 우리가 이전에 배웠던 const 키워드는 변하지 않는 상수 값을 저장하는 키워드라 하였다. 그래서
const value = 3; value = 5; 이렇게 값을 바꾸려 들면 에러가 났었다!!

그렇지만 객체나 배열 같이 참조형 변수는 const로 그 값을 수정할 수 있다.

왜냐면 참조형 변수는 객체 값이 아니라 주소를 가리키고 있기 때문이다!! 그래서 내부 프로퍼티를 수정해도, 변수에 담긴 주소 값 자체는 바뀌지 않는 것이다.

사실 JS에서는 const 키워드를 쓰는 것을 권장하기 때문에, 참조형 변수를 선언할 때엔 const를 쓰는 습관을 들이는 것도 좋아보인다.