6. 데이터 타입




값의 종류

원시타입

  • 숫자 타입
  • 문자열 타입
  • 불리언 타입
  • undefined 타입
  • null 타입
  • 심벌 타입

객체 타입

  • 객체, 함수, 배열

  • 1 ≠= “1” 생성한 목적과 용도가 다르다.
  • 확보해야할 메모리 공간, 2진수, 읽어 들여 해석하는 방식 모두 다르다.

숫자 타입

  • 정수, 실수를 구분하지 않는다.
  • 배정밀도 64비트 부동소수점 형식의 2진수로 저장
  • 모든 수를 실수로 처리, 정수만을 위한 별도의 타입 x
var binary = 0b01000001; //2진수
var octal = 0o101; // 8진수
var hex = 0x41; // 16진수

console.log(binary) //65
console.log(octal) //65
console.log(hex) //65
// 표기만 다를 뿐 모두 같은 수이다.
console.log(1 === 1.0) // true
  • Infinity : 양의 무한대
  • -Infinity : 음의 무한대
  • NaN : 산술 연산 불가 (Not a number)
  • js는 대소문자를 구별하므로, NAN, nan, Nan하면 에러 (이 값들을 값이 아닌 식별자로 해석한다.)
let x = nan
//ReferenceError: nan is not defined
console.log(x)

문자열 타입

  • 텍스트 데이터
  • 0개 이상의 16비트 유니코드 문자(UTF-16)의 집합으로, 전 세계 대부분의 문자 표현 가능
  • 문자열을 따옴표를 감싸는 이유 : 키워드나 식별자 같은 토큰과 구분하기 위해
  • 감싸지 않으면, 스페이스 같은 공백문자 포함 x
// 따옴표로 감싸지 않으면 hello를 식별자로 인식한다.
let str = hello
//ReferenceError: hello is not defined
  • c : 문자열 타입 없이 문자의 배열로 문자열 표현
  • java : 객체로 문자열 표현
  • js : 문자열은 원시타입으로, immutable 하다.

템플릿 리터럴

  • ES6에서 도입
  • 멀티라인 문자열, 표현식 삽입, 태그드 탬플릿 등 제공
  • 런타임에 일반 문자열로 변환되어 처리한다.
  • 백틱 (``) 사용

멀티라인 문자열

let common = "hello
줄 바꿈!"
// SyntaxError: Invalid or unexpected token

let template = `hello
줄 바꿈~!`
console.log(template)
// hello
// 줄 바꿈~!
  • 일반 문자열은 개행을 허용하지 않는다. > 사용하려면 이스케이프 시퀀스 사용해야함
  • 템플릿 리터럴에서는 이스케이크 시퀀스를 사용하지 않고도 줄바꿈 허용. 모든 공백 있는 그대로 적용

이스케이프 시퀀스

  • \0 : Null
  • \b : 백스페이스
  • \f : 폼 피드 : 프린터로 출력할 경우 다음 페이지의 시작 지점으로 이동
  • \n : 개행, 다음 행으로 이동 (Line Feed)
  • \r : 개행, 커서를 처음으로 이동 (Carage Return)

os마다 개행방식이 다르다. 윈도우 : CR + LF 유닉스 : LF mac : LF 다른 OS에서 작성한 텍스트 파일은 서로 개행 문자를 인식하지 못하지만, 텍스트 에디터에서 OS에 맞게 개행문자를 자동으로 변환해준다. js에서는 일반적으로 LF(\n)을 사용해 개행한다.

  • \t : 탭(수평)
  • \v : 탭(수직)
  • \uXXXX : 유니코드 (\u0041 : ‘A’)
  • ' : 작은 따옴표
  • " : 큰 따옴표
  • \ : 백슬래시

표현식 삽입

  • 문자열은 문자열 연산자 +를 사용해 연결할 수 있다.
  • +연산자는 피연산자 중 하나 이상이 문자열인 경우, 문자열 연결 연산자로 동작
var first = 'nahyun'
var last = 'jo'

console.log(`my name is ${first} ${last}`)
// my name is nahyun jo
  • ${표현식} 에 들어가는 표현식의 평가 결과가 문자열이 아니어도 문자열로 강제 형변환 된다.
console.log(`1 + 2 = ${1+2}`)
//1 + 2 = 3

불리언 타입

  • 논리적 참, 거짓을 나타내는 true, false

undefined 타입

  • undefined 가 유일
  • var 키워드로 선언한 변수는 암묵적으로 undefined 로 초기화
  • 변수 선언에 의해 확보된 메모리 공간을 처음 할당이 이뤄질 때까지 쓰레기값으로 내버려두지 않고, undefined로 초기화한다.
  • undefined는 개발자가 의도적으로 할당하기 위한 값이 아닌, js 엔진이 변수를 초기화할 때 사용하는 값
  • 변수 참조시 undefined가 반환된다면, 초기화되지 않은 변수란 것을 파악 가능
  • 따라서, 개발자가 의도적으로 undefined를 할당하는 것은 취지에 어긋나므로 권장x
  • 그러면 변수에 값이 없음을 나타내고 싶을 땐??? null

선언(declaration)과 정의(definition) js 의 undefined 의 정의 : 변수에 값을 할당하여 변수의 실체를 명확하게 하는 것. 다른 언어는 선언과 정의를 엄격하게 구분한다. (실제로 메모리 주소를 할당하는가?) c) 선언 : 단순히 컴파일러에게 식별자의 존재만 알리는 것 정의 : 실제로 컴파일러가 변수를 생성해서 식별자와 메모리 주소가 연결되는 것 js는 변수를 선언하면 암묵적으로 정의가 이루어지기 때문에 구분이 모호한다. ECMAScript에서는 변수는 선언한다, 함수는 정의한다 라고 표현한다.

null 타입

  • null 이 유일
  • 대소문자 구분하므로 Null, NULL 과 다르다
  • 변수에 값이 없다는 것을 의도적으로 명시(의도적 부재)할 때 사용
  • 변수에 null 할당 : 변수가 이전에 참조하던 값을 더이상 참조하지 않겠다라는 의미
  • 이전 참조되던 값은 GC가 수행됨
var foo = "Jo"
// 이전 참조를 제거. foo변수는 더이상 "Jo"를 참조하지 않는다.
// 유용해 보이지 않는다. 변수의 스코프를 좁게 만들어 변수 자체를 재빨리 소멸시키는 편이 낫다.
foo = null
  • 함수가 유요한 값을 반환할 수 없는 경우 명시적으로 null을 반환하기도 한다(html의 document.querySelect는 메서드 조건에 부합하는 html요소를 찾지 못했을 경우 null을 반환)

심벌 타입

  • ES6에서 추가
  • 변경 불가능한 원시 타입의 값
  • 다른 값과 중복 되지 않는 유일무이한 값
  • 주로 이름이 충돌할 위험이 없는 객체의 유일한 프로퍼티 키를 만들기 위해 사용된다.
  • 심벌 이외의 원시 값은 리터럴을 통해 생성하지만 심벌은 Symbol 함수를 호출해 생성
  • 이때 생성된 심벌값은 외부에 노출x, 다른 값과 절대 중복되지 않는 유일무이한 값
var key = Symbol('key')
console.log(typeof key) //symbol

var obj = {}
// 이름이 충돌할 위험이 없는 유일무이한 값인 심벌을 프로퍼티 키로 사용한다.
obj[key] = 'value'
console.log(obj[key]) //value

// obj["key"] = 'value'
// console.log(obj["key"]) //value
// 이거랑은 다른거야!

객체 타입

  • 원시타입과 객체타입은 근본적으로 다르다.
  • js는 객체 기반의 언어이며, js를 이루고 있는 거의 모든 것이 객체

데이터 타입의 필요성

데이터 타입에 의한 메모리 공간의 확보와 참조

  • 메모리에 값을 저장하려면 확보해야할 메모리 공간의 크기를 결정해야 한다.
  • 데이터 타입(값의 종류)에 따라 정해진 메모리 공간을 확보한다.

ECMAScrip 사양은 문자열과 숫자 타입 외의 데이터 타입은 크기를 명시적으로 규정 x 따라서 문자열, 숫자 이외의 데이터 타입에 따라 확보되는 메모리 공간은 js 엔진 제조사마다 다르다.

  • 참조하는 경우.
  • 식별자 score를 통해 숫자 타입 100 이 저장된 메모리 공간 주소를 찾아간다. (100이 저장되어 있는 메모리 공간의 선두 메모리 셀의 주소)
  • 한번에 읽어들여야 할 메모리 공간의 크기 (메모리 셀의 갯수(바이트 수))를 알아야 한다.

심벌 테이블 : 컴파일러 또는 인터프리터는 심벌 테이블이라고 부르는 자료구조를 통해 식별자를 키로 바인딩된 값의 메모리 주소, 데잍터 타입, 스코프 등을 관리한다.

데이터 타입에 의한 값의 해석

  • 메모리에서 읽어들인 2진수를 어떻게 해석해?
  • 메모리에는 2진수(비트의 나열)로 저장되며, 데이터타입에 따라 다르게 해석해야 한다.
  • ex 0100 0001은 숫자로 해석시 65, 문자로 해석시 ‘A’
  • score변수에 할당된 값은 숫자 타입의 값이다. 따라서 score 변수를 참조하면 메모리 공간의 주소에서 읽어 들인 2진수를 숫자로 해석한다.

데이터 타입의 필요성

  • 값을 저장할 때 확보해야 하는 메모리 공간의 크기를 결정하기 위해
  • 값을 참조할 때 한번에 읽어들여야할 메모리 공간의 크기를 결정하기 위해
  • 메모리에서 읽어 들인 2진수를 어떻게 해석할지 결정하기 위해

동적 타이핑

동적 타입 언어와 정적 타입 언어

  • js의 모든 값은 데이터 타입을 갖는다. 그렇다면 변수는?
  • c,java 같은 정적 타입언어는 변수를 선언할 때, 데이터 타입을 선언해야 한다. (명시적 타입 선언)
  • 정적 타입 언어는 컴파일 시점에 타입 체크(선언한 데이터 타입에 맞는 값을 할당했는지 검사하는 처리) 수행
  • 타입 체크 통과 못하면, 에러 > 타입의 일관성을 강제한다.
  • js는 변수를 선언할 때 타입을 선언하지 않고, var, let, const 키워드를 사용하여 선언할 뿐이다.
  • js는 미리 선언한 데이터 타입의 값만 할당할 수 있는 것이 아닌, 어떠한 데이터 타입의 값이라도 자유롭게 할당 가능
  • typeof 연산자를 통해 변수에 할당된 값의 데이터 타입을 반환
  • js는 값을 할당하는 시점에 변수의 타입이 동적으로 결정되고, 변수의 타입을 언제든지 자유롭게 변경 가능
  • js의 변수는 선언이 아닌 할당에 의해 타입이 결정된다.(=== 타입 추론)
  • 그리고 재할당에 의해 변수의 타입은 언제든지 동적으로 변할 수 있다. (=== 동적 타이핑)
  • 변수는 타입을 가질까? 가지지 않는다!
  • 하지만 값은 타입을 갖는다.
  • 현재 변수에 할당되어 있는 값에 의해 변수의 타입이 동적으로 결정된다. (변수는 값에 묶여 있는 값에 대한 별명이기 때문)

동적 타입 언어와 변수

  • 동적 데이터 타입 언어의 장점 : 데이터 타입에 대해 무감각해질 정도로 편리하다.
  • 단점 : 복잡한 프로그램에서 변화하는 변수 값을 추적하기 어렵다.
  • 값을 확인하기 전에는 변수의 타입을 확신할 수 없다.
  • Js는 개발자의 의도와 상관없이 js 엔진에 의해 암묵적으로 타입이 자동 변환되기도 한다.
  • 동적 타입 언어는 유연성은 높지만 신뢰성은 떨어진다.

변수 사용 주의사항

  • 꼭 필요한 경우에 한해 제한적으로 사용
  • 변수의 유효 범위(스코프)를 최대한 좁게 만든다.
  • 전역 변수 사용 자제
  • 변수보다는 상수 사용 > 값의 변경 억제
  • 변수 네이밍은 목적이나 의미 파악 가능하도록 (존재 이유가 드러나도록)