210103 스터디 발표 준비(대본형)

발표: https://docs.google.com/presentation/d/1xuQnVmiKMlXd3ac0K_5ANsE1qBOtC0dvGgtQZY-Oi3M/edit?usp=sharing

안녕하세요, c조 발표를 맡게 된 ㅁㅁㅁ 입니다.
c조는 코어 자바스크립트를 중심으로 한 학습으로 목표를 잡았고, 지난 스터디 기간동안 데이터 타입에 대해 학습하고 발표를 준비했습니다.
발표 시작하도록 하겠습니다.

자바스크립트 데이터 타입을 크게 두 가지로 나누자면 기본형, 그리고 참조형이 있습니다.
기본형에는 숫자, 문자열, 불리언, null, undefined가 있고, ES6에서 심볼이 추가되었습니다.
참조형에는 객체, 배열, 함수, 날짜, 정규식 등이 존재합니다. Map, WeakMap, Set, WeakSet 등은 객체의 하위 분류에 속하게 됩니다.

방금 데이터 타입은 크게 기본형, 참조형으로 나뉘게 된다고 말씀드렸는데, 기본형과 참조형의 차이를 구분짓는 것은 바로 "할당이나 연산시 이루어지는 복제"가 어떻게 이루어지느냐 입니다.
이를 이해하기 위해서는 몇 가지 배경지식이 필요한데요, 필요 배경 지식을 간단하게 훑고 지나가도록 하겠습니다.

컴퓨터는 모든 데이터를 0 또는 1로 바꿔 기억한다는 점은 다들 익히 들어 알고 계실거라고 생각합니다.
0 또는 1 하나로 구분되어있는 메모리 조각을 비트라고 표현하고, 각 비트는 고유한 식별자를 지닙니다. 이 비트 8개로 이루어진 한 단위를 1 바이트라고 표현하는데요, 바이트 또한 시작하는 비트의 식별자로 위치를 파악할 수 있습니다. 모든 데이터는 바이트 단위의 식별자, 더 정확하게는 메모리 주솟값을 통해 서로 구분하고 연결할 수 있습니다.

다음으로는 식별자와 변수에 대해 알아보겠습니다. 흔히 변수와 식별자를 혼용해 사용하곤 하는데요, 대부분의 경우 문맥에 따라 무엇을 말하고자 하는지 유추가 가능하기 때문입니다.
하지만 정확하게 분리하자면 식별자는 데이터를 식별하기 위한 이름, 즉 변수명이고 변수는 데이터가 담길 수 있는 공간을 의미합니다. 위의 코드var a = 30;을 해석하자면 곧, 변할 수 있는 데이터를 만든다. 이 데이터의 식별자는 a이고, 데이터의 값으로 30을 할당한다. 라고 해석할 수 있습니다.

이제부터 직접적으로 변수에 데이터가 할당이 될 때 어떤 일이 일어나고, 또 어떤 방식으로 복제가 이루어지는지에 대해 알아보도록 하겠습니다.

다음의 사진은 이해를 돕기 위해 개략적으로 설명된 그림이고, 실제 데이터 구조는 이보다 더 복잡하다고 합니다. 발표에서는 이와 같이 개략적으로 설명된 그림을 가지고 설명을 진행하도록 하겠습니다.
a라는 이름을 가진 데이터에 'abc'라는 값을 할당할 때 다음과 같은 구조를 띄게 됩니다.
변수 영역의 1003이라는 주솟값을 가진 곳에 이름은 a, 값은 주소값 5004를 가진 데이터가 지정됩니다. 5004는 데이터 영역에 존재하고, 이 5004의 값은 'abc'를 가지고 있습니다.
즉, 변수 영역에서 값을 직접 가지고 존재하는게 아니라 데이터 영역의 주소값을 값으로 가지고, 실제 데이터는 5004라는 주소를 가진 영역에서 가지고 있게 되는거죠.

사진만 보면 사실 굉장히 비효율적인 방식이라고 생각할 것 같습니다.
하지만 이것은 데이터 변환을 자유롭게 할 수 있게 함과 동시에 메모리를 더욱 효율적으로 사용하기 위한 고민의 결과값이라고 볼 수 있다고 합니다.(페이지 넘기기) 예를 들어, 데이터를 확보된 공간 내에서만 변환할 수 있다고 한다면, 다른 데이터들의 주소값까지 변경하고 옮기고 해야하는 불필요한 과정들이 뒤따를 것입니다. 따라서 더 효율적인 관리를 위해 어떤 변환을 가하든 상관없이 무조건 새로운 공간을 확보해 별도로 지정하고, 그 공간의 주소값을 변수 영역의 값에 지정해주는 방식을 택하게 된 것이라고 합니다.

그럼 이렇게 이루어지는 할당의 과정이 어떻게 기본형과 참조형을 구분짓게 되었는지에 대해 알아보도록 하겠습니다.

기본형 데이터는 기본적으로 '불변성'이라는 특징을 지니고 있다고 알고 있습니다. 불변성이란 데이터 영역 메모리의 변경이 불가능함을 특징으로 가지고 있게 되는 것이죠. 즉, 어떤 식별자의 실제 데이터가 변경되는 과정에 있어서 해당 주소에 위치한 데이터가 직접 변경되는 것이 아니라, 다른 데이터 주소값에 값이 저장이 되고, 변수 영역 데이터에는 그 주소가 대입되게 됩니다.

하지만 가변성 값에 있어서는 조금 다르게 방향이 진행됩니다.
그림을 보시면, 식별자에 대한 값의 주소를 따라 가보면, 객체 프로퍼티가 지정되어있습니다.
즉, 프로퍼티 주소값을 값으로 가지고 있고, 그 프로퍼티의 값에 대입되어진 주소를 따라가면 우리가 원하는 객체 프로퍼티의 데이터 값을 얻을 수 있게 됩니다.
다음과 같이 프로퍼티의 값이 변경되게 되면, 식별자의 값의 주소가 변경이 되는게 아니라 프로퍼티에서 가지고 있는 주소값이 변경되게 됩니다.

즉 가변성과 불변성의 가장 큰 차이점은 식별자의 값이 바라보는 주소값이 변경되느냐, 변경되지 않느냐로 구분되어질 수 있고, 이는 곧 기본형과 참조형 데이터를 구분짓는 기준이라고 볼 수 있습니다.

기본형 데이터와 참조형 데이터는 복사에 있어서도 차이점을 가지게 됩니다.
다음과 같은 식이 있습니다.

var a = 10;
var b = a;

var obj1 = { c: 10, d: 'ddd' };
var obj2 = obj1

밑의 데이터 구조를 분석하면, 1001과 1002의 값에 대입된 a, b 는 같은 5001 데이터 주소를 바라보고 있습니다. obj1 과 obj2는 5002 주소값을 바라보고 있고, 5002 주소의 값은 7103번부터 7104번까지의 프로퍼티 c, d 를 가리키고 있고, 각각은 또 다히 5001, 5003의 주소를 바라보고있습니다.

여기서, b와 obj2의 c 값을 변경할 때 a와 obj1의 값은 어떻게 될까요?

a는 10, obj1은 { c: 20, d: 'ddd' }의 값을 가지게 됩니다. wow.
어째서 a의 값은 변경되지 않았는데 obj1의 값은 변경되게 된걸까요?
그건 바로 불변성, 가변성의 특징에 따라 값이 바라보는 데이터 주소값의 변경/미변경에서 비롯됩니다.
b는 기본형 데이터의 불변성 특징에 따라 본인이 바라보고 있는 데이터의 주소값이 바뀌었기 때문에 a에 지장을 주지 않았지만, obj1과 obj2가 바라보는 주소값은 가변성 특징에 따라 동일한데, 7103이 바라보는 데이터의 주소값은 변경되었기 때문에 다음과 같은 차이가 발생하게 되는 것 입니다.

즉, 기본형 데이터는 복제되어 생성된 변수의 데이터가 변경되어도 기존의 변수에는 영향을 미치지 않지만, 참조형 데이터는 데이터가 복제되어 생성된 변수의 데이터가 변경될 경우 기존의 변수에까지 영향을 미치게 됩니다.
복제된 객체의 데이터 값을 변경할 때 마다 기존 객체의 데이터 값이 변경된다면 우리는 계속해서 새로운 객체, 새로운 프로퍼티를 계속해서 작성해줘야 할 것이고 이것은 곧 비효율적인 코드작성으로 이루어질것입니다.
따라서 어떻게 하면 기존 객체를 변경하지 않으면서, 복제된 객체의 데이터 값을 변경할 수 있을지에 대해 알아보도록 하겠습니다.

가장 간단한 방법은 1. 데이터 재할당입니다. 재할당이라 함은 새로운 객체를 만들고, 그 객체 안에 변경될 값을 직접 작성해준 후 그 데이터를 바라보게 변수가 가지는 값의 주소를 변경해버리는 것을 의미합니다.
하지만 계속해서 그런 식으로 코드를 바꿔주는 것 또한 비효율적입니다. 그것을 대안하는 방법이 바로 2. 객체를 복사하는 함수를 생성해 새로운 객체를 리턴해주도록 하는 방법입니다.

두 함수는 두 번째, 새로운 객체를 리턴해주도록 하는 방식의 데이터 복제를 도와주는 함수입니다.
첫 번째 함수는 프로퍼티를 계속해서 작성해줘야한다는 불편함을 가지고 있기 때문에, 두 번째 함수와 같이 복제의 타겟이 되는 오브젝트 'target'에 for in 문을 통해 프로퍼티를 가지고 오고, 그 프로퍼티를 통해 값을 가져와 복제 한 값을 result라는 새로운 object에 담아 그 result를 리턴해주도록 합니다.

이렇게 하면 기존 객체에 영향을 주지 않고 데이터를 변경할 수 있을 것 같지만, 한 가지 우리가 놓치는 부분이 있습니다. 위와 같은 방식으로 객체를 복제할 경우 바로 아래 단계의 값만 복사를 하기 때문에 중첩되어있는 객체에서 주소값만 복사되기 때문에 이전에 말했던 문제가 다시금 발생하게 됩니다.

이처럼 바로 아래 단계의 값만 복사하는 것을 얕은 복사라고 하고, 내부의 모든 값을 하나하나 다 찾아서 전부 복사하는 것을 깊은 복사라고 합니다.

왼쪽의 함수는 얕은 복사를 해주는 함수이고, 오른쪽은 깊은 복사를 해주는 함수입니다.
나 자신을 다시 호출하는 재귀 함수를 사용해서, 계속해서 프로퍼티 안의 객체를 복제할 수 있도록 하고 있습니다.

마지막으로는 undefined와 null 인데요, undefined는 존재하지 않는 데이터에 사용자가 접근하려고 하는 경우 자바스크립트 엔진에서 부여해줍니다. 물론, 사용자가 직접 명시적으로 지정해주는 것 또한 가능합니다.

존재하지 않는 데이터에 대한 결과가 undefined라면, 비어있는 값은 null 입니다.
null값을 체크하기 위해서는 몇 가지 주의할 점이 있는데요, typeof와 동등 연산자(==)를 사용할 경우 제대로 된 값을 체크할 수 없다는 점입니다.

null의 type을 체크하면 Object가 나오고, 동등 연산자를 사용할 경우 undefined와 비교했을 때 true를 반환하므로, null을 체크하기 위해서는 일치 연산자(===)를 사용해줘야합니다.

좋은 웹페이지 즐겨찾기