프론트앤드

컴퓨터 프로그래밍 자바스크립트 데이터 타입과 연산자

머리큰개발자 2023. 2. 1. 20:21

데이터 타입


데이터 타입은 왜 필요할까?

가장 먼저 데이터를 메모리에 저장하기 위해 공간의 크기를 계산해야 한다.
그리고 데이터를 읽어올 때 필요한 데이터의 크기만큼 읽어와야 한다.
데이터를 크기만큼 읽어오고 어떻게 해석해야 할지 정해야 한다.
(이를 위해 심벌 테이블에 식별자를 키로 만들어서 메모리 주소와 타입, 스코프를 관리한다.)

위 세 가지 이유 때문에 데이터 타입이 필요한 것이다.


자바스크립트 7개의 데이터 타입을 가진다.(ES6 ~ )
기본적으로 C언어에서 출발했기 때문에 비슷한 면도 있지만 사뭇 다른 타입들도 등장했다.
종류는 두 가지로 나뉜다.
원시 타입(Primitive type)과 객체 타입(object type)이다.



원시 타입에 다음 6가지가 속한다.

  1. 숫자(Number) 타입
  2. C와 다르게 정수와 실수의 구분이 없고, 모든 숫자를 포함.
  3. 64비트 부동소수점을 사용하므로 c의 double 가 같은 precision을 가진다.
  4. Infinity, -Infinity, NaN(산술 불가, 대소문자 주의)의
  5. 세 가지 특수한 값을 추가로 가질 수 있다.
  6. 문자열(String) 타입
  7. UTF16을 사용해서 전 세계 문자 표현 가능.
  8. 변경 불가능한 값이므로 ‘ㅁ’ 이 ‘ㅁㄴ’으로 바뀔 경우 ㄴ을 추가하는 것이 아닌, 새로 할당된다.
  9. ‘’, “”, `` 으로 감싸서 표현하며, ES6부터 등장한 템플릿 리터럴 ``은
  10. 줄 바꿈, 태그, 변수(${})를 문자열에 포함시킬 수 있다.
  11. 불린(Boolean) 타입
  12. True or False
  13. undefined
  14. 선언했지만 할당하지 않은 변수에 할당되는 값
  15. Null
  16. 값이 0이 아니라 아예 없다는 것을 명시적으로 사용
  17. Symbol
  18. ES6에서 등장한 불변값으로 앱 내에서 유일한 값을 가진다.
  19. 같은 값을 initial value로 주어도 다른 값을 리턴한다.
  20. 객체 타입엔 객체, 함수, 배열 등 위 6가지에 해당하지 않는 타입이 모두 속한다.


자바스크립트는 특별하다.
흔치 않은 동적 타입의 변수를 지원한다.
동적 타입의 변수란 타입이 고정되어 있지 않고,
개발자가 할당하는 대로 타입이 변한다는 뜻이다.
동적 타입의 변수는 뜻하지 않은 실수들을 많이 일으키는데,
잘못 할당하여 타입이 바뀌는 경우,
자바스크립트 엔진에 의해 암묵적으로 타입이 바뀌었지만
인식하지 못하고 있던 경우 등이 있다.
파이썬, PHP, 루비, 리스프, 펄 등도 동적 타입의 언어다.

해결하는 방식은, 네이밍 컨벤션을 잘 맞춘다던지, 스코프를 잘 쓴다던지 하는 식이 있지만
최근에는 타입스크립트의 도입으로 타입을 명시하고
타입이 변경될 경우 에러를 유발하는 방식이 가장 널리 쓰이고 있는 것 같다.
본래 자바스크립트가 웹서비스를 위해서 탄생했다는 것을 생각해 보면,

어찌 되었든 화면은 나오긴 해야 하므로 유연성을 선택하고
신뢰성을 포기했다고 생각할 수 있다.

  • cf) Symbol?
  • 유일한 프로퍼티 키를 만들 때 사용한다.
  • Const s = Symbol(‘init’) ;
  • 처럼 함수로 호출하며, init 값이 같더라도 다른 값을 내놓는다.
  • 암묵적 변환이 되지 않는 고유 값이지만 boolean 에선 truthy 값을 가진다.
  • 기본적으로 symbol.iterator, symbol.for, symbol.keyFor 등의 메서드가 제공된다.
  • 상수 값을 정의하거나
  • Ex) Const exObject = { A : Symbol(‘A’)};
  • 프로퍼티를 은닉할 때 사용한다.

연산자


연산자는 하나 이상의 표현식으로 연산을 수행하여 하나의 값을 만든다.
연산자는 수행하는 역할로도 구분할 수 있고,
연산에 쓰이는 피연산자의 개수로도 구분할 수 있다.

2-1. 산술 연산자

피연산자를 대상으로 수학적 계산을 수행한다.
산술 연산이 불가능한 경우에 한하여 NaN을 리턴한다.

피연산자가 두 개 필요한 이항 산술 연산자와 한 개가 필요한 단항 산술 연산자가 있다.

이항 산술 연산자 연산
+ 덧셈, 피연산자 중 하나가 문자열이면 문자열로 자동 변환한다. 1 + ‘2’ = ‘12’
- 뺄셈
* 곱셈
/ 나눗셈
% 나머지 (mod)
단항 산술 연산자 연산
++ 증가
-- 감소
+ 의미 없음
- 부호 반전



2-2. 할당 연산자

할당 연산자 연산
= 할당
+= a += 5 는 a = a+5 와 동일하다
-= a -= 5 는 a = a-5 와 동일하다
*= a *= 5 는 a = a*5 와 동일하다
/= a /= 5 는 a = a/5 와 동일하다
%= a %= 5 는 a = a%5와 동일하다.



2-3. 비교 연산자

비교 연산자 연산
== 동등 비교, x==y 면 x와 y의 값이 같은지.
=== 일치 비교, x===y 면 x와 y의 값과 타입까지 확인한다.
!= 부동등 비교, x!=y 면 x와 y의 값이 다른지.
!== 불일치 비교, x!==y면 x와 y의 값과 타입까지 다른지 확인한다.
> x>y 면 x 가 y 초과인지.
<  
>= x>=y 이면 x가 y 이상인지.
<=  


자바스크립트는 동등/비동등 비교일 경우 타입이 다르면 타입을 일치시킨 후 비교한다.
1 == ‘1’ 일 경우 ‘1’을 1로 변환한 후 1 == 1을 비교하기 때문에 true를 반환한다.

하지만 1 === ‘1’의 경우 타입이 다르기 때문에 false를 반환한다.

자바스크립트는 굉장히 이상하게 동작하기 때문에 인터넷에도 밈이 많다.
https://www.codeguage.com/courses/js/data-types-quiz
위 페이지에서 타입 맞추기 퀴즈를 해보자.
당신은 얼마나 맞출 수 있는가.

그렇기 때문에 결과를 예측하기 힘들고,
그렇다고 외우기도 힘드니
헷갈린다 싶으면 타입 디버깅을 꼭 하자.

2-4. 논리 연산자

논리 연산자 연산
|| OR 연산, a||b 이면 a가 참이면 a, a가 거짓이면 b를 반환한다.
&& AND 연산, a&&b 이면 a가 참이면
! NOT 연산


논리 연산을 할 때는 단축 평가가 들어간다.
논리 연산의 속도를 높이고 쓸모없는 연산 횟수를 줄일 수 있다.
이 말은 다시 말해, 최종 반환값이 꼭 True와 False 가 아니라는 뜻이다.

예를 들어서
let a = ‘A’ || ‘B’;
가 있다면 a 에는 어떤 값이 들어갈까?

‘A’는 true로 간주되므로 'A' || 'B'에서 'A'에서 true 가 판별되고
즉시 'A'를 반환하므로,
a = ‘A’가 된다.

규칙을 한 번 보면 다음과 같다.

논리 연산 평가 결과
true || A true
false || A A
True && A A
False&& A false


이는 해당 연산을 생략하고도 truthy나 falsy 값을 반환하는 것으로
연산 결과가 바뀌지 않기 때문이다.
이를 통해 약간의 속도 증가가 있다.

단축 평가는 굉장히 많이 쓰이는 패턴이므로 익혀두면 좋다.

가령 props를 받았는데 이 값이 비었을 경우 default 값을 넣을 수 있다.

function(propName) { let name = propName || ‘defaultName’; }

2-5. 삼항 조건 연산자

A? B : C : A가 참이면 B, 거짓이면 C를 리턴한다.
if else와 동일한 논리이지만, 식에 쓸 수 있다.

즉, let a = 5 > 7? ‘맞았습니다 ‘ : ’ 틀렸습니다 ‘; 이면
a = ‘틀렸습니다’가 들어간다.
위 식은

let a; 
if (5 > 7) { a = ‘맞았습니다‘; } 
else { a = ‘틀렸습니다’; }

와 동일한 뜻이다.

2-6. 쉼표 연산자와 그룹 연산자, typeof 연산자, 지수 연산자

쉼표 연산자는 왼쪽부터 차례대로 수행하고,
맨 오른쪽에 있는 연산이 끝나면 마지막 값을 반환한다.

let a,b,c;

a = 1, b = 2, c = 3 // 3 반환



그룹 연산자는 ()로 사용하며, 우선순위를 가장 높인다.
() 안에 있는 연산이 우선 시행된다.

3 * ( 1 + 2 ) // 9



typeof 연산자는 앞서 7가지 데이터 타입에서
null이 빠지고 function이 들어간 타입들을 반환한다.

var a = 1;

typeof a // Number



지수 연산자는 ** 를 사용한다. Math.pow() 보다 가독성이 좋다.
음수를 밑으로 사용하려면 괄호를 써야 한다. (-5) ** 2 === 25;

2-7. 고급 연산자

연산자 연산자 이름 기능
?. 옵셔널 체이닝 연산자 A?.property;
A가 객체인지 null/undefined 인지 체크한다.
null, undefined 인 경우 없는 property에 접근한다고 에러를 내지 않고 undefined를 반환한다.
?? null 병합 연산자 ES11에 도입된 최-신 문법
a??b일 경우 a가 null/undefined 일 경우 b를 반환한다.
|| 와 유사하게 사용되지만, null 과 undefined만 판별한다.
0과 ‘’일 때도 통과시켜주므로 ||와 다르다.
delete   프로퍼티 삭제. delete(a.name) 하면 a에서 name 프로퍼티를 삭제한다.
New   인스턴스 생성
Instance of   객체가 우변의 생성자 함수로 부터 생성된 인스턴스인지 판별
in   프로퍼티가 객체 안에 존재하는지 확인

2.8 연산자의 우선순위

순위 연산자
1 ()
2 new(매개변수), ., [] (프로퍼티), () (함수호출), ?. (옵셔털 연산자)
3 new()
4 X++, x—;
5 !x, +x, -x, ++x, —x, typeof, delete (단항)
6 ** (제곱)
7 *, /, %
8 +, -
9 <, <=, >, >=, in, instanceof
10 ==, !=, ===, !==
11 ?? (null 병합 연산자)
12 &&
13 ||
14 Condition ? true : false (삼항 조건 연산자)
15 =, +=, -=, *=, /=, %=
16 ,


자주 쓰는 것들은 다 예상 가능한 범위이므로,
모두 외우지 말고 필요할 때마다 검색해서 쓰도록 하자.

연산자 결합순서도 있긴 한데, 연속적으로 쓰는 경우가 많지 않아서 생략한다.

우선순위와 결합순서가 헷갈린다면 괄호를 적극적으로 활용하도록 하자.
나에게 헷갈리는 것은 남들도 헷갈릴 가능성이 높기 때문에
가독성 좋게 쓰는 것이 우선이다.