데이터 타입

귤양·2021년 4월 7일
0

Javascript

목록 보기
2/10
post-thumbnail

아래 내용은 학원 수업과 "모던자바스크립트 Deep Dive : 이웅모 저"를 읽고 정리한 내용입니다.

1. 데이터 타입이 필요한 이유?

앞서 말한 것 과 같이 값을 재사용하기 위해서는 메모리에 저장하고, 참조할 수 있어야 한다. 그런데 이 값을 메모리에 저장하기 위해서는 값의 크기를 알아야 한다. 값을 메모리 공간에 저장하기 위해서는 메모리 공간을 미리 확보해야 하는데, 값은 데이터 타입에 따라 필요한 메모리 공간의 크기가 전부 다르다. (메모리 공간을 미리 확보하는 이유는 한정되어 있는 메모리 공간을 효율적으로 사용하기 위해서이다.) 값은 결국 컴퓨터가 읽을 수 있는 이진수로 변환되어 메모리 공간에 저장된다. 이 값을 다시 참조할 때 한번에 읽어야 할 메모리 공간의 크기를 알아야 하고, 또 데이터 타입을 알아야 2진수 값을 제대로 해석할 수 있게 되는 것이다. 만약 데이터 타입을 모른다고 가정했을 때 한번에 읽어야 할 메모리 공간의 크기를 잘못 측정하여 이진수가 짤려서 넘어오게 되면, 해석된 값은 전혀 다른 값이 될 것이고, 같은 이진수라도 해석하는 데이터 타입에 따라서 전혀 다른 값이 될 수 있기 때문이다.

2. 자바스크립트의 데이터 타입

: 자바스크립트에는 7가지 데이터 타입이 있고, 크게 원시 타입객체 타입으로 나눌 수 있다.

  • 원시타입
    • 숫자(number)
    • 문자열(string)
    • 불리언(boolean)
    • undefinde
    • null
    • symbol
  • 객체타입

2-1. 원시타입

숫자(Number)

자바스크립트는 모든 숫자를 실수로 처리한다. (정수로 보여도 사실은 실수이다.)

추가적으로 infinity(양의 무한대), -infinity(음의 무한대), NaN(산술 연산 불가 : not a number, 대소문자 표기 중요!)의 값도 있다.

문자열(string)

문자열은 16비트 유니코드 문자(utf-16)들의 집합으로 전 세계 대부분의 문자를 표현할 수 있다. 문자를 표현할 때는 작은 따옴표(''), 큰 따옴표(""), 백틱(`` )으로 표현할 수 있다.

템플릿 리터럴

템플릿 리터럴은 백틱``을 이용한 문자열 표기법이며, 여러가지 편리한 표기법을 지원한다.

  1. 멀티라인 문자열
    기존의 문자열 표기법으로는 줄바꿈과 같은 표현을 하기가 쉽지 않았다. 하지만 템플릿 리터럴 표기법은 줄바꿈과 모든 공백이 그대로 적용된다.

  2. 표현식 삽입
    기존의 문자열 표기법에서는 문자열과 문자열을 연결하기 위해서는 + 연산자를 사용해야 했다. 때문에 일반 문자열과 변수에 담긴 값 등을 연결해서 사용하기가 복잡했다. 하지만 템플릿 리터럴에서는 표현식 삽입 기능을 통하여 쉽게 사용할 수가 있다.

console.log(`1 + 2 = ${1 + 2}`); // 1 + 2 = 3

불리언(boolean)

불리언 타입은 논리적 참, 거짓을 나타내는 true, false를 말하고, 조건문에서 많이 사용된다.

undefined

undefinedundefined가 유일한 값이며, var키워드로 선언한 변수는 암묵적으로 undefined로 초기화된다. 변수에 값을 할당하기 전에는 undefined가 할당되어 있는 것이다. 이 처럼 undefined는 값이 할당되지 않은 상태를 나타낼 때 사용한다. 이 때문에 undefined를 개발자가 임의로 사용하게 되면 혼란을 줄 수 있기 때문에 개발자가 직접 사용하지 않아야 한다.

null

nullnull이 유일한 값이며, 일반적으로 변수에 값이 없다는 것을 의도적으로 명시적으로 표시하고 싶을 때 사용한다.

symbol

ES6에서 추가된 7번째 타입으로, 다른 값과 중복되지 않는 유일한 값이다.

2-2. 객체타입

객체

객체는 {}안에 0개 이상의 프로퍼티로 구성(빈 객체를 생성할 수도 있기 때문에 프로퍼티가 없어도 가능하다는 뜻이다.)된 집합이며, 프로퍼티는 다시, 프로퍼티 키와 프로퍼티 값으로 구성되어 있다. 자바스크립트에서는 프로퍼티 값에 함수도 포함될 수 있으며 프로퍼티의 값이 함수일 경우 일반 함수와 구분하기 위해서 이 것을 메서드(method)라고 부른다. 다시 말하면 객체는 프로퍼티 키와 프로퍼티 값으로 구성된 프로퍼티 또는 메서드(method)로 구성될 수 있다.
이 때 프로퍼티 키는 빈 문자열을 포함하는 모든 문자열 또는 심벌 값으로 자유롭게 작성할 수 있다. 하지만 앞선 포스팅에서 언급했던 식별자 네이밍 규칙을 준수하는 프로퍼티키와 준수하지 않은 프로퍼티 키에는 약간의 차이가 있으므로 가능하면 식별자 네이밍 규칙을 준수하는 것이 좋다.

var user = {
	name : 'kyuree', // 식별자 네이밍 규칙을 준수하는 경우
    'user-gender': 'female' // 식별자 네이밍 규칙을 준수하지 않는 경우
}

프로퍼티 값 갱신

이미 존재하는 프로퍼티에 값을 할당하면 해당하는 프로퍼티의 값이 갱신된다.

프로퍼티 동적 생성

존재하지 않는 프로퍼티에 값을 할당하면 프로퍼티가 추가되고, 값이 할당된다.

프로퍼티 삭제

객체는 delete 연산자를 이용하여 프로퍼티를 삭제할 수 있다. 단, 존재하지 않는 프로퍼티를 삭제하려고 하면 에러가 발생하는 것이 아니라 무시된다.

프로퍼티 축약 표현

객체 리터럴의 프로퍼티 값은 변수에 할당된 값일수도 있다. 이 때 ES6의 경우 프로퍼티 값에 할당하려는 변수와 프로퍼티 키의 이름이 같을 경우에는 축약 표현을 사용할 수 있다.

let name = 'kyuree';

// 프로퍼티의 값에 할당하려는 변수의 식별자와 프로퍼티 키가 동일한 경우 사용 가능한 축약표현
const person = {name}

console.log(person); // {name: 'kyuree'}

메서드 축약 표현

위에서 언급되었지만, 객체의 값에 함수를 할당한 프로퍼티는 메서드라고 한다. 이 때 ES6의 경우 function 키워드를 생략한 축약 표현을 사용할 수 있다.

const person = {
	name: 'kyuree',
    // function 키워드를 생략한 메서드 축약표현
    sayHi() {
    	console.log('Hi! + this.name);
    }
}

obj.sayHi(); // Hi! kyuree

배열

배열은 []안에 여러개의 값을 순차적으로 나열한 기본적이고, 사용빈도가 매우 높은 자료구조이다. 배열은 length 프로퍼티를 갖고 있으며, 배열 안의 값들은 0부터 시작되는 숫자로 된 인덱스를 통해서 접근이 가능하다.

var user = ['kyuree, 'hyacinta']

객체와 배열의 값 참조

일반 변수에 담긴 원시값은 변수를 참조하게 되면 원하는 값이 보이게 된다. 하지만 객체와 배열을 담은 변수를 참조하게 되면 객체와 배열의 전체가 보이게 된다. 그런데 객체와 배열에 들어있는 일부 값만 참조해서 사용하고 싶을 때는 어떻게 하면 될까?

객체의 값 참조

객체는 프로퍼티를 가지고 있다고 했고, 이 프로퍼티는 프로퍼티 키와 프로퍼티 값으로 구분되다고 했다. 우리가 객체의 값을 사용한다는 것은 이 프로퍼티중 프로퍼티 값을 사용하고자 한다는 것이다. 그런데 이 값을 참조하기 위해서는 반드시 프로퍼티 키가 필요하다. 바로 아래의 코드처럼 마침표 표기법을 사용하여 참조할 수 있는 것이다.

// user 객체의 name 프로퍼티를 참고하려고 함.
var user = {
	name: 'kyuree',
    'user-gender': 'female'
}
console.log(user.name) // 'kyuree'

하지만 위의 코드는 프로퍼티 키가 식별자 네이밍 규칙을 준수하고 있다는 전제하게 사용할 수 있는 코드이다. 만약 프로퍼티 키가 식별자 네이밍 규칙을 준수하고 있지 않다면, 아래와 같은 대괄호 표기법을 사용하여 객체의 값을 참조하여야 한다.

// user 객체의 'user-gender' 프로퍼티를 참고하려고 함.
var user = {
	name : 'kyuree',
    'user-gender' : 'female'
}
console.log(user['user-gender']) // 'female'

만약 프로퍼티 키가 숫자로 되어 있다면 아래의 코드처럼 대괄호 안에 '' 혹은 ""를 생략해도 된다.

var user = {
	1 : 'kyuree',
    2 : 'hyacinta'
}

console.log(user[1]) // 'kyuree'

하지만, 프로퍼티키를 식별자 네이밍 규칙에 준수하여 작성한다면 사용하지 않아도 될 몇 글자를 더 작성해야 하는 수고를 덜 수 있으므로 식별자 네이밍 규칙을 준수하여 프로퍼티 키를 작성하는 것이 좋겠다.

배열의 값 참조

배열은 length 프로퍼티를 가지고 있으며, 각 값은 0부터 시작하는 인덱스를 가지고 있다고 했다.
배열에서 값을 참조하기 위해서는 이 인덱스를 알고 있어야 하며, 값을 참조하는 방법은 아래의 코드와 같다.

// user 배열읠 첫번째 요소를 참조하고자 함. 
var user = ['kyuree', 'hyacinta']
console.log(user[0]) // 'kyuree'

그런데 위에서 보이는 배열의 참조 방법이 어딘가 낯이 익다. 바로 객체에서 식별자 네이밍 규칙을 준수하지 않은 프로퍼티키로 참조했던 대괄호 표기법이다. 사실 배열은 인덱스를 나타내는 0이상의 숫자를 프로퍼티키로 가지고 있는 객체인것이다. 때문에 대괄호 표기법을 사용해서 값을 참조할 수 있으며 프로퍼티키가 숫자로 시작하기 때문에 대괄호 안에 '' 혹은 ""를 생략할 수 있는 것이다.

3. 원시값과 객체의 비교

3-1. 원시값

변경불가능한 값

원시값은 단순하게 말해서 변경할 수 없는 값이다. 하지만 주의해야 할 것은 여기서 말하는 변경이 불가능 하다는 것이 값을 말하는 것이지, 변수에 저장되는 값이 변경될 수 없다는 말이 아니다. 무슨 말장난인가 싶을 수도 있을 것 같다.

변수(variable)은 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해서 붙인 이름을 말한다. 즉 값이 저장되어 있는 메모리 공간의 위치를 가리키고 있는 상징적인 이름인 것이다.
"모던자바스크립트 Deep Dive : 이웅모 저"

앞선 포스팅에서 언급한 변수의 정의다. 이 말을 다시 해석하면 변수가 가르키고 있는 것은 값 자체가 아닌 값이 저장되어 있는 메모리 공간을 가르키고 있다는 것이다.

이 것을 바탕으로 원시값이 변경 불가능한 값이라는 것을 설명하자면, 변수에 저장되어 있는 것이 원시값일 때 다른 메모리 공간에 다른 원시값을 저장하고, 그 값이 저장되어 있는 메모리 공간을 다시 가르키는 것이 변수의 재할당이다. 하지만 변수가 이미 가르키고 있는 메모리 공간에 있는 원시값을 다른 원시값으로 변경할 수는 없다는 말이다.

값에 의한 전달

위에서 말했듯 원시값은 변경이 불가능한 값이라고 했다. 때문에 원시값을 복사하면 값에 의한 전달이 일어나는데, 이 값에 의한 전달을 설명해보고자 한다.

var score = 80;
var copy = score;

console.log(score === copy); // true

위 코드에서 score를 복사한 copy변수의 값은 score와 동일한 값이라는 것을 알 수 있다. 다른 변수지만 같은 값이라는 소리다.

var score = 80;
var copy = score;

score = 100;
console.log(score === copy) // false

하지만, 이 두번째 예제 코드에서 score를 재할당 한 뒤에 두 변수를 비교해 보면 결과는 false가 나온다. 분명 copy는 score를 복사했는데, 왜 이런 결과가 나왔는지 생각해보자.

원시값이 저장되어 있는 변수를 복사하면 저장되어 있는 원시값을 복사하여 다른 메모리 공간에 저장하고, 복사하고자 하는 변수명이 해당 메모리 공간을 가르키도록 하는 것이다. 때문에 변수를 복사한 이후에 기존 변수의 값을 재할당하고, 두 변수를 비교하면 재할당 된 100이라는 값과 재할당 이전에 복사되었던 80이라는 값을 비교하게 되므로 false라는 결과가 나오게 되는 것이다.
이 처럼 원시값은 값을 복사하여 복사하고자 하는 다른 변수에 전달하므로 값에 의한 전달이라고 표현을 한다.

3-2. 객체

객체, 배열 과 같은 객체 타입의 값은 안에 포함되는 프로퍼티의 개수가 정해져있는 것이 아니라, 동적으로 추가되거나 삭제할 수 있으며 프로퍼티의 값에도 제약이 없다. 때문에 객체는 원시값과 같이 확보해야 할 메모리 공간의 크기를 사전에 정해 둘 수 가 없다.

변경 가능한 값

변경이 불가능한 원시값을 가진 변수는 값을 변경하려면 재할당 외에는 방법이 없다. 하지만, 객체는 재할당이 없이도 값을 변경하는 것은 물론이고, 동적으로 값을 추가하거나 삭제하는 것도 가능하다. 이 것은 객체타입의 값을 담고 있는 변수는 객체 타입의 값을 직접 가르키고 있는 것이 아니라, 객체 타입의 값을 가르키고 있는 참조값을 가진 메모리 공간을 가르키고 있기 때문이다.

객체 타입은 프로퍼티의 값이 다양한 타입이 될 수 있고, 심지어는 객체의 프로퍼티 값이 객체일수도 있다. 또한 객체는 동적으로 프로퍼티를 추가하거나 삭제, 변경할 수 도 있기 때문에 사용해야 할 메모리 공간이 유동적이다. 이렇게 복잡한 구조인 객체를 한정된 자원안에서 효율적으로 사용하기 위해서는 객체를 담고 있는 변수가 객체를 담고 있는 메모리 공간을 직접 가르키는 것이 아니라, 객체를 담고 있는 메모리 공간의 참조값을 가르키고 있는 것이다.

참조에 의한 전달

위에서 설명한 것과 같이 객체는 변경이 가능한 값이고 그 이유는 객체를 가르키고 있는 변수가 값을 직접 가르키는 것이 아니라 객체가 담겨 있는 메모리 공간을 가르키고 있는 메모리 주소 값을 가지고 있기 때문이라고 했다.
이 것을 코드로 확인해보자.

var user = {
	name : 'kyuree',
    gender : 'female'
}
var copy = user;

console.log(user === copy); // true

위 코드에서 console.log를 통해 확인된 결과를 보면 user 변수와 copy 변수가 가르키고 있는 객체는 같다는걸 알 수 있다.

var user = {
	name : 'kyuree',
    gender : 'female'
}
var copy = user;

copy.name = 'Kim kyuree';

console.log(score === copy) // true

위의 코드를 원시값을 복사해서 변수에 새로 값을 할당했던 경우와 비교해 보자. 원시값의 경우에는 변수를 복사한 뒤에 복사한 변수에 새로운 값을 할당한뒤 복사 대상이었던 변수와 복사한 뒤 새로운 값을 할당한 변수를 비교하면 false가 나왔다. 하지만 객체를 복사한 위의 코드에서는 같은 값이라고 나온다. 이 것은 객체를 복사할 때는 값에 의한 복사가 아니라 참조에 의한 전달. 즉 참조값을 복사해서 전달해주기 때문이다.

조금 더 자세히 살펴보기 위해서 또 다른 코드를 살펴보도록 하자.

var user = {
	name : 'kyuree',
    gender : 'female'
}
var copy = user;

console.log(user); // {
	name : 'kyuree',
    gender : 'female'
}
console.log(copy); // {
	name : 'kyuree',
    gender : 'female'
}

user.job = 'frontend developer';
console.log(user); // {
	name : 'kyuree',
    gender : 'female',
    job : 'frontend developer'
}
console.log(copy); // {
	name : 'kyuree',
    gender : 'female',
    job : 'frontend developer'
}

코드를 보면 객체를 담고 있는 원래의 변수에 프로퍼티를 추가했을 때, 해당 객체를 복사한 다른 변수에서도 동적으로 추가된 프로퍼티를 참조할 수 있다. 객체를 복사하게 되면, 객체가 저장되어 있는 메모리 공간의 주소를 복사해서 가지게 되고, 결국 객체를 할당한 각각의 변수는 하나의 객체를 가리키고 있기 때문이다.

profile
디자인하는 Frontend Developer.

0개의 댓글