자바스크립트- 데이터 타입 정리

김민지·2020년 9월 9일
1
post-thumbnail

데이터 타입의 종류

자바스크립트 데이터 타입은 기본형, 참조형 이렇게 크게 두가지로 볼 수 있다.
일전 자바스크립트 이해하기-2 에서도 간략하게 살펴보았었지만 책을 읽고 정리해보면서 더욱 자세하게 살펴보려고한다.

이 둘을 구분하는 기준은 무엇일까?

둘 다 복제를 하지만 기본형은 값이 담긴 주솟값을 바로 복제하고, 참조형은 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복제한다는 점이 다르다. (이 부분은 예시로 살펴보면 이해가 수월하게 된다.)

데이터 타입에 관한 배경지식

메모리와 데이터

모든 데이터는 바이트 단위의 식별자, 더 정확하게는 메모리 주솟값을 통해 서로를 구분하고 연결할 수 있다.

컴퓨터는 모든 데이터를 0 또는 1로 바꿔 기억한다. 하나의 메모리 조각을 비트라고 하고, 메모리는 많은 비트들로 구성되어 있는데 각 비트는 고유한 식별자를 통해 위치를 확인할 수 있다.

이런 비트를 한 단위로 묶으면 검색 시간을 줄일 수 있고 표현할 수 있는 데이터의 개수도 늘어나지만 동시에 낭비되는 비트도 생긴다. 이런 고민의 결과로 바이트(byte)라는 단위가 생겼다. 1바이트는 8개의 비트로 구성되어있고 1비트마다 0 또는 1의 두가지 값을 표현할 수 있으므로 1바이트는 총 256개의 값을 표현할 수 있다.

정적 타입 언어(C/C++,java)는 메모리의 낭비를 최소화하기 위해 데이터 타입별로 할당 메모리 영역을 정해놓았다. 숫자형 데이터를 저장할 경우 정해진 숫자만 허용하고 이상의 숫자를 입력하면 오류가 나거나 잘못된 값이 저장되므로 이를 대처하기 위해서는 사용자가 직접 변환해야하는(int) 번거로운 작업이 필요했다.

한편 메모리 용량이 과거보다 월등히 커진 상황에서 등장한 자바스크립트는 상대적으로 메모리 관리에 대한 압박에서 자유로워졌다. 때문에 메모리 공간을 좀 더 넉넉하게 할당했고 위와같은 번거로운 상황이 덜 발생하게 되었다.

식별자와 변수

변수는 '변할 수 있는 데이터' 이고 식별자는 어떤 데이터를 식별하는데 사용하는 이름, 즉 변수명 이다.

변수 선언과 데이터 할당

변수 선언

var a;

변수란 변경 가능한 데이터가 담길 수 있는 공간, 또는 그릇이다. 어떤 변수를 선언하면 컴퓨터는 메모리에서 a라는 변수명을 가진 주소를 검색해 해당 공간에 담긴 데이터를 반환할 것이다.

데이터 할당

var a;
a = 'abc';

var a='abc';

a라는 이름을 가진 주소를 검색해서 'abc'라는 문자열을 할당할 때 해당 위치에 문자열 'abc'를 저장하고, 그 주소를 변수 영역에 저장하는 식으로 이루어진다.

변수 영역에 값을 직접 대입하지 않고 굳이 번거롭게 한단계를 거치는 이유는 바로 데이터 변환을 자유롭게 할 수 있게 함과 동시에 메모리를 더욱 효율적으로 관리하기 위함이다.

예를 들어 숫자형과 다르게 문자열은 특별히 정해진 데이터 규격이 없기 때문에 메모리 용량이 가변적이다. 만약 미리 확보한 공간 내에서만 데이터 변환을 하게된다면, 변환된 데이터를 다시 저장해야할 경우 확보된 공간을 변환된 데이터 크기에 맞게 늘리는 작업이 선행되어야 한다. 이 때 중간에 있는 데이터라고 가정한다면 해당 공간보다 뒤에 저장된 데이터들을 전부 뒤로 옮기고, 이동시킨 주소를 각 실별자에 다시 연결해야하는 번거로움이 발생한다.

결국 효율적으로 문자열 데이터의 변환을 처리하려면 변수와 데이터를 별도의 공간에 나누어 저장하는 것이 최적의 방법이다.

어떤 변수에서 문자열을 저장하고 나중에 새로 문자열을 추가할 경우, 저장된 공간에 바뀐 데이터를 할당하는 것이 아닌 변경될 데이터를 새로 만들어 별도의 공간에 저장하고 그 주소를 변수 공간에 연결한다.

즉 변수명이 데이터를 저장하는 방식은 위에서 언급했던 것 처럼 직접 데이터를 저장하는 것이 아니라 해당 데이터를 가진 주솟값을 저장하는 것!

때문에 중복된 데이터를 처리할 때에도 효율성이 높아지는 장점이 있다.

기본형 데이터와 참조형 데이터

불변값

변수(variable)와 상수(constant)를 구분하는 성질은 변경 가능성이다.
이 변경 가능성의 대상은 변수 영역 메모리이다.
즉 한 번 데이터 할당이 이뤄진 변수 공간에 다른 데이터를 재할당할 수 있는지의 여부가 관건이다.

반면 불변성 여부를 구분할 때의 변경 가능성의 대상은 데이터 영역의 메모리이다.

기본형 데이터는 모두 불변값이다.
기본형 데이터를 저장할 때에 한 번 저장된 기본형 데이터는 다른 값으로 변경이 불가능하다. 변경은 새로 만드는 동작을 통해서만 이뤄진다. 한 번 만들어진 값은 가비지 컬렉팅을 당하지 않는 한 영원히 변하지 않는다.

가변값

참조형 데이터는 기본적인 성질이 가변값인 경우가 많지만 설정에 따라 변경 불가능한 경우도 있고 아예 불변값으로 활용하는 방안도 있다.

참조형 데이터와 기본형 데이터의 차이는 '객체의 변수(프로퍼티)영역'이 별도로 전재한다는 점이다. 데이터 영역에 저장된 값은 모두 불변값이지만 변수에는 얼마든지 다른 값을 대입할 수 있기 때문에 흔히 참조형 데이터는 불변하지 않다(가변값이다)라고 한다.

변수 복사 비교

보통 기본형은 값을 복사하고 참조형은 주솟값을 복사한다고 하지만, 사실 엄밀히 따지면 자바스크립트의 모든 데이터 타입은 참조형 데이터일 수 밖에 없다.

다만 기본형은 주솟값을 복사하는 과장이 한 번만 이뤄지고, 참조형은 한단계를 더 거친다는 차이가 있다.

불변 객체

불변 객체를 만드는 간단한 방법 & 얕은 복사와 깊은 복사

값으로 전달받은 객체에 변경을 가하더라도 원본 객체는 변하지 않아야 하는 경우에 불변객체가 필요하다.

참조형도 기본형과 마찬가지로 새로운 데이터를 할당하고자 할 때 기존 데이터는 변하지 않는다. 내부 프로퍼티를 변경할 필요가 있을 때마다 매번 새로운 객체를 만들어 재할당 하기로 규칙을 정하거나 자동으로 새로운 객체를 만드는 도구를 활용하면 객체 역시 불변성을 확보할 수 있다.

규칙이라함은 얕은 복사, 깊은 복사 방법을 활용하여 새로운 객체를 반환하는 함수를 만드는 방법 또는 immutable.js, baobab.js 등의 라이브러리를 활용하는 방법 있다.

//얕은 복사
//for in 문법을 이용하여 result 객체에 target 객체의 프로퍼티들을 복사

var copyObj = function (target) {
  var result = {};
  for( var prop in target) {
    result[prop] = target[prop];
  }
  return result;
};

//깊은 복사
//target이 객체인 경우 내부 프로퍼티들을 순회하며 copyObjDeep함수를 재귀적으로 호출하고 객체가 아닌 경우 target을 그대로 지정
var copyObjDeep = function(target) {
  var result = {};
  if (typeof target === 'object' && target !== null) {
    for (var prop in target) {
      result[prop] = copyObjDeep(target[prop]);
    }
  } else {
    result = target;
  }
  return result;
};

//결과 확인

var object = {
  a: 1,
  b: {
    c: null,
    d: [1, 2]
  }
};

var object2 = copyObjDeep(object);

object2.a = 3;
object2.b.c = 4;
object.b.d = 3;

console.log(object); // { a: 1, b: { c: null, d: [1, 3]}}
console.log(object2);// {a: 3, b: { c: 4, d: {0: 1, 1: 2}}}

undefined 와 null

'없음'을 나타내는 값

undefined
자바스크립트 엔진은 사용자가 응당 어떤 값을 지정할 것이라고 예상되는 상황임에도 실제로는 그렇게 하지 않았을 때 undefined를 반환한다.

값을 대입하지 않은 변수
객체 내부의 전재하지 않는 프로퍼티에 접근
return문이 없거나 호출되지 않는 함수의 실행 결과
배열의 경우에는 조금 특이하게 동작하는데, 아래 예시로 살펴보면

var arr1 = [];
arr1.length = 3;
console.log(arr1); // [empty x 3]

var arr2 = new Array(3);
console.log(arr2); // [empty x 3]

var arr3 = [undefined, undefined, undefined];
console.log(arr3); // [undefined, undefined, undefined]

'비어있는 요소'와 'undefined를 할당한 요소'는 출력 결과부터 다르다.
사용자가 명시적으로 부여한 경우와 비어있는 요소에 접근하려 할 때 반환되는 두 경우를 미루어 보아 'undefined'의 의미를 구분할 수 있다. 전자의 경우는 하나의 값으로 동작하고, 후자의 경우 값이 없음을 나타낸다.

같은 의미를 가진 null은 비어있음을 명시적으로 나타낼 때 사용한다.

때문에 undefined를 직접 할당하지 않는다면 두 데이터 타입의 차이를 명확히 구분지어서 사용할 수 있다.

null을 사용시에 한가지 주의해야할 점은 typeof null이 object라는 점이다. 따라서 어떤 변수의 값이 null인지 여부를 판별하기 위해서는 동등 연산자가 아닌 일치연산자를 사용해야 정확히 판별할 수 있다.

책 : 코어 자바스크립트 _ 정재남 지음

profile
Welcome~!

0개의 댓글