자바스크립트에도 데이터 타입이 있다.
데이터 타입에는 원시타입(Primitive type) 과 객체타입( Object/ Reference type)이 있다.
원시타입
- 숫자 -> 정수, 실수 구분없이 하나의 숫자 타입만 존재한다. 배정밀도 64비트 부동소수점으로 해석된다. 즉 모든 수를 실수로 처리한다는 뜻이다. 3 / 2를 하면 1.5로 처리된다는 뜻이다. 숫자 타입에는 추가적으로 Infinity, -Infinity, NaN(Not a Number)가 있다.
- 문자열
다른 언어와는 달리 문자열을 생성할 때 ""(큰 따옴표)와 ''(작은 따옴표) 구분 없이 사용할 수 있다. ES6에는 템플릿 리터럴이 추가되었다. 템플릿 리터럴은 멀티라인 문자열, 표현식 삽입, 태그드 템플릿의 기능을 제공한다.
템플릿 리터럴을 쓰는 방식은 백틱(``)을 이용해서 문자열을 만들면 된다.
var x = '멀티
라인 제공 안함
'; // Uncaught SyntaxError: Invalid or unexpected token
var x = `멀티
라인 제공 함
`;
console.log(x);
// 멀티
// 라인 제공함
var name = 'coding';
console.log('hello ' + name); // 기존의 문자열 결합
console.log(`hello ${name}`; // 템플릿 리터럴 태그드 리터럴
console.log('1 + 1'); // 1 + 1
console.log(`${1 + 1}`); // 2 템플릿 리터럴 표현식 삽입
- 불리언
true, false
- undefined
undefined 타입은 undefined가 유일하다.
- null
null 타입 또한 null이 유일하다.
- 심벌 타입
ES6도입, 변경 불가능한 원시 값 선언할 때 사용, 다른 값과 중복되지 않는 유일 무이한 값
이름이 충돌할 위험이 없는 객체의 유일한 프로퍼티 키를 만들기 위해 사용
var 키워드로 선언한 변수는 암묵적으로 undefined로 초기화 된다.
-> 변수 선언에 의해 확보된 메모리 공간을 처음 할당이 이뤄질 때까지 빈상태(대부분 비어있지 않고 쓰레기값이 들어있다)로 내버려두지않고 자바스크립트 엔진이 undefined로 초기화한다.
자바스크립트 엔진이 변수를 초기화 하는데 사용하는 undefined를 개발자가 의도적으로 변수에 할당한다면 undefined의 본래 취지와 어긋날 뿐더러 혼란을 줄 수 있으니 변수에 직접적으로 undefined를 명시하는 것은 지양하자.
만약 변수에 값이 없는 것을 명시하고 싶을 때는 null을 할당하자.
함수가 유효한 값을 반환할 수 없는 경우에는 명시적으로 null을 반환하기도 한다. (ex) document.querySelector로 엘리먼트 못찾으면 null반환
자바스크립트는 객체 기반 언어이며, 자바스크립트를 이루고 있는 거의 모든 것이 객체이다.
데이터 타입이 왜 중요한가?
값은 메모리에 저장하고 참조할 수 있어야한다. 메모리에 값을 저장하려면 메모리 공간을 확보하고, 값을 저장해야한다.
그러면 어느정도 크기의 메모리 공간을 확보해야할까? 1바이트? 4바이트??
데이터 타입을 알면 몇 바이트의 메모리 공간을 사용해야 낭비와 손실 없이 값을 저장할 수 있는 지 알 수 있기 때문에 데이터 타입은 중요하다.
값의 저장
var score = 100; 라고 변수 선언과 값의 할당을 했다고하면
1. 메모리 공간 확보
2. undefined로 초기화
3. 확보된 메모리에 숫자 값 100을 2진수로 저장
의 순서를 진행한다.
이 때 메모리 공간의 크기는 어느 정도 할 것인지 자바스크립트 엔진은 데이터 타입에 따라서 정해진 크기의 메모리 공간을 확보한다. (변수에 할당되는 값의 데이터 타입에 따라 확보해야할 메모리 공간의 크기가 결정)
위의 경우에는 숫자 타입이기 때문에 배정밀도 64비트 부동소수점이기에 8바이트의 공간을 확보할 것이다.
값의 참조
1. 식별자를 통해 값이 저장된 메모리 주소를 찾아간다. 정확히 말하면 선두 메모리 셀의 주소를 찾아간다.
2. 값을 참조한다. => (어느 정도 크기의 메모리 공간을 한번에 읽어야할까????)
값을 참조하려면 한번에 읽어들여야 할 메모리 공간의 크기, 즉 메모리 셀의 개수(바이트 수)를 알아야한다. 저장된 값이 숫자 타입이면 8byte 단위로 읽어들인다. 그렇게 하지 않으면 값이 훼손 될 것이다.
그러면 컴퓨터는 한번에 읽어들여야 할 메모리 셀의 크기를 어떻게 알 수 있을까??
변수에 할당된 값의 데이터 타입이 숫자 타입이므로 자바스크립트 엔진은 숫자 타입을 인식해서 8바이트 단위로 메모리 공간에 저장된 값을 읽어들일 것이다.
그러면 읽어온 2진수 값을 어떻게 해석할까??
0100 0001(2) => 이 값은 숫자로 해석하면 65, 문자로 해석하면 'A'이다.
변수를 통해 주소에 접근 후 데이터 타입에 따라 바이트 단위로 읽어 들여온 2진수는 숫자 타입으로 해석하냐, 문자 타입으로 해석하냐에 따라 값이 달라진다. -> 이것 또한 변수에 할당된 값의 타입을 기반으로 해석한다.
데이터 타입이 필요한 이유 3개
1. 값을 저장할 때 확보해야 하는 메모리 공간 크기를 결정하기 위해
2. 값을 참조할 때 한번에 읽어들여야 할 메모리 공간의 크기를 알기 위해
3. 메모리에서 읽어들인 2진수를 어떻게 해석할 지 결정하기 위해
위에는 값의 데이터 타입을 다루었다. 그러면 변수는 데이터 타입을 가질 수 있을까??
다른 언어(C, Java)같은 경우에는 변수 선언 시 변수에 할당할 수 있는 값의 종류 즉, 데이터 타입을 사전에 선언한다.(명시적 타입 선언) 이러한 언어를 정적 타입 언어라고 한다.
한번 선언한 변수의 타입은 변경이 불간으하고, 변수에 선언한 타입에 맞는 값만 할당이 가능하다.
정적타입언어는 컴파일 시점에 타입체크(선언한 데이터에 맞는 값을 할당했는지 검사하는 처리)를 수행한다.
그런데 자바스크립트는 var, let, const 키워드로 변수를 선언을 할 수는 있지만 할당 가능한 데이터 타입을 선언할 수는 없다. typeof연산자로 변수를 연산하면 변수의 데이터 타입을 변환하는 것으로 알 수 있지만, 이것도 정확히 말하면 변수의 데이터 타입이 아니라 변수에 할당된 값의 데이터 타입을 반환하는 것이다.
자바스크립트에서는 값을 할당하는 시점에 변수의 타입이 동적으로 결정이 된다. 자바스크립트는 동적 타입 언어이다. 변수의 타입은 언제든지 자유롭게 변경이 가능하다. 예시를 통해 보자
var a ;
console.log(typeof a); // undefined
a = 10; // 할당 시점에 숫자로 데이터 타입 변경
console.log(typeof a); // number
a = '1'; // 다른 타입을 넣어도 동작한다.(문자 타입으로 변경)
console.log(typeof a); // string
자바스크립트 변수는 선언이 아닌 할당에 의해서 타입이 결정(type interface)된다. 그리고 재할당에 의해 변수의 타입은 언제든지 동적으로 변경이 가능하다(동적 타이핑)
연산자
연산자란 하나 이상의 표현식을 대상으로 산술, 할당, 비교, 논리, 타입, 지수 연산을 수행해서 하나의 값을 만든다.
연산의 대상을 피연산자라고 부르며 피연산자는 표현식이어야한다.
산술 연산자
- 이항 산술 연산자 (피연산자가 2개) + , -, *, /, %
피연산자를 대상으로 수학적 계산을 수행해 숫자값을 만든다. 불가능한 경우 NaN반환 ( 1 / 'hello'와 같은 경우 )
피연산자의 값을 변경하는 Side Effect가 없다.
- 단항 산술 연산자 (피연산자가 1개) ++, --, +, -
++, -- 증감연산자의 경우는 피연산자의 값을 변경하는 Side Effect 존재
+ -> 숫자 타입이 아닌 피연산자에 + 단항 연산자를 사용하면 피연산자를 숫자 타입으로 변환해서 반환한다.
이때, 피연산자를 변경하는 것이 아니라 숫자 타입으로 변환한 값을 생성해서 반환하므로 Side Effect 존재 x
(undefined는 숫자로 타입 변환이 되지 않는다. +undefined => NaN);
- -> - 단항 연산자 또한 숫자타입이 아닌 피연산자에 사용하면 숫자타입으로 변환하여 반환한다. 차이점은 부호를 반전한 값을 리턴한다는 것이다. 마찬가지로 Side Effect 존재 x
문자열 연결 연산자
자바스크립트에서 + 연산자는 피연산자 중 하나이상이 문자열이라면 문자열 연결 연산자로 동작이 된다.
1 + 'hello' => '1hello'
타입 강제 변환
1 + true => 2
true를 1로 변환하여 2로 연산이 되었다. 자바스크립트 엔진에 의해서 암묵적으로 타입이 자동으로 변환 되기도 한다.
암묵적 타입 변환(Implicit Coercion) 또는 타입 강제 변환(Type Coercion)이라고 한다.
할당 연산자 ( = , +=, -=, *=, /=, %=)
변수의 값을 변경하기에 부수효과(Side Effect)가 존재한다.
표현식은 값으로 평가될 수 있는 문이다. 할당문은 과연 표현식일까?
할당문은 변수에 값을 할당하는 부수효과가 있을 뿐, 값으로 평가가 안될 줄 알았다. 하지만 할당문은 값으로 평가되어 표현식인 문으로서 할당된 값으로 평가된다. 이 특성을 이용해서 연쇄 할당도 가능하다.
var a, b, c;
a = b = c = 10
console.log(a, b, c) // 10 10 10
비교 연산자(compare Operator)
좌항과 우항의 피연산자를 비교해서 boolean 값을 반환한다.
- 동등 비교 연산자
암묵적 타입 변환을 통해서 타입을 일치시킨 후 비교를 진행한다. (1 == '1') -> true
- 일치 비교 연산자
타입도 같고 값도 같아야 true를 반환한다. (1 === '1') -> false
일치 비교 연산자여도 NaN 비교, 양의 0 과 음의 0 비교는 안된다. ( +0 === -0 ) =>true (NaN === NaN) -> false
해결) Object.is(val1, val2)를 이용하면 비교가 가능하다, 또한 Number.isNaN 메소드를 이용해서 NaN인지 판별 가능
삼항 조건 연산자 (ternary operator)
조건식의 평가 결과에 따라 반환할 값을 결정한다. ( 조건식 ? 조건식이 true일 때 반환값 : 조건식이 false일 때 반환값)
if..else는 값으로 사용이 불가능하지만 삼항 조건 연산자는 가능하다.
변수에 값을 조건에 따라서 할당할 때 사용하자.
typeof 연산자
typeof 연산자를 이용하면 해당 피연산자의 타입을 알 수 있지만, typeof null -> object로 나오는 등 위에서 설명한 원시값과 일치하지 않는 점이 있다는 것을 유의하자.
* 선언하지 않은 식별자에 typeof 연산자를 연산하면 Reference Error가 아니라 undefined를 반환한다.
제어문
제어문은 조건에 따라 코드블록을 실행(조건문) 하거나 반복실행(반복문) 할 때 사용한다.
블록문 (block statement / compound statement)
-> 0개이상의 문을 중괄호로 묶은 것, 코드 블록 또는 블록이라고도 한다.
자바스크립트는 블록문을 하나의 실행단위로 취급한다. 블록문은 문의 종료를 의미하는 자체 종결성을 갖기 때문에 블록문의 끝에는 세미콜론을 붙이지 않는다.
조건문 (conditional statement)
주어진 조건식(conditional expression)의 평가결과에 따라 블록문의 실행을 결정하는 문이다.
조건식이라는 것은 boolean값으로 평가될 수 있는 표현식이다. boolean이 아닌 값을 평가하면 자바스크립트 엔진에 의해 암묵적으로 불리언값으로 강제 변환이 일어나고 평가된다.
if..else문, switch문이 있다
var x = 1;
if (x === 1) {
console.log('hello'); //실행이 된다.
}
if (x === 2) {
console.log('bye'); // 실행 x
} else {
console.log('zizi'); // 실행됌.
}
switch문은 주어진 표현식을 평가하여 그 값과 일치하는 표현식을 갖는 case문으로 실행블록을 옮긴다.
switch문의 표현식과 일치하는 case문이 없다면 default문으로 이동한다.
var x = 'hello';
var result;
switch(x){
case 'h': // 콜론을 사용해서 케이스를 나타냄
result = 'h';
case 'ell':
result = 'ell';
case 'hello':
result = 'hello';
default:
result = 'default';
}
console.log(x);
// default가 출력된다. (fall through 폴스루가 일어나서 case 'hello'에 조건을 만족했지만
// break문을 통해서 빠져나가지 않아서 case 'hello': 문 아래에 있는 코드가 다 실행이 되었다.
var x = 'hello';
var result;
switch(x){
case 'h': // 콜론을 사용해서 케이스를 나타냄
result = 'h';
break;
case 'ell':
result = 'ell';
break;
case 'hello':
result = 'hello';
break;
default:
result = 'default'; // default문은 break문 생략가능 보통 맨 아래에 있어 쓰지 않는다.
}
console.log(x); // hello
반복문
- for문, while문, do while문
주로 for문은 반복횟수가 명확할 때 사용하고, while문은 반복횟수가 불명확할 때 주로 사용한다.
for문
for(선언문 or 할당문; 조건식; 증감식) {
// 실행할 코드 내용
}
for(var i = 0; i <2; i++) {
console.log(i);
}
// 0
// 1
for문 실행순서를 보자
1. 맨 먼저 변수 선언문 or 할당문이 실행된다. 이는 단 한번만 실행된다.
2. 변수 선언문 실행이 종료되면 조건식이 실행된다. 평가결과가 참이면 코드블록을 실행한다.
3. 코드 블록 실행 종료시 증감식 실행 후 다시 조건식을 실행한다.
4. 이 과정에서 조건식의 평가결과가 true면 다시 코드 블록을 실행한다, 만약 false면 for문 실행을 종료한다.
break문, continue문
break문은 코드블록을 탈출할 때 사용한다 정확히 말하면 레이블문, 반복문, switch문을 탈출할 때 사용한다.
레이블문이란 식별자가 붙은 문이다. foo: console.log('foo');
continue문은 반복문의 코드블록 실행을 현지점에서 중단하고 반복문의 증감식으로 실행흐름을 이동시키는 문이다.
//문자열 내부에 해당 문자열의 개수 찾기
var string = 'Hello world';
var search = 'l';
var count = 0;
for(var i=0; i< string.length; i++) {
if(string[i] !== search) continue;
count++;
}
console.log(count); // 3
// 아래에 string.prototype.match 메소드로도 구현 가능
const regexp = new RegExp(search, 'g');
console.log(string.match(regexp).length); // 3
'모던 자바스크립트 Deep Dive' 카테고리의 다른 글
자바스크립트 Deep Dive 2일차 (변수, 표현식과 문) (0) | 2022.06.29 |
---|---|
모던 자바스크립트 Depp Dive 공부 1일차 (0) | 2022.06.27 |