[코어 자바스크립트] 1. 데이터 타입

홍예찬·2020년 12월 15일
0
post-thumbnail

Epilogue

3개월간의 위코드 부트캠프가 끝나고 어떤 공부를 더 해야할까 고민했습니다.
부트캠프의 특성상 자바스크립트를 포함한 다양한 라이브러리, 프레임워크에 대한 원론적이고 심층적인 개념 이해보다는 실무에 바로 투입될 수 있는 역량을 기르는데에 초점이 맞춰져있기 때문에 잘 이해되지 않는 개념이라 하더라도 이해보다는 적용에 힘썼습니다.

부트캠프 수료 후, 그 무엇보다 자바스크립트 언어에 대한 탄탄한 이해가 필요하다는 생각이 들었습니다.
따라서 위코드를 수료한 동료 개발자분들과 함께 코어 자바스크립트라는 책을 중심으로 스터디를 진행하면서 부족했던 자바스크립트에 대한 기초 다지기 작업을 해야겠다는 생각이 들었습니다.

자바스크립트에 대한 기초적인 개념의 이해와 ES6 공부를 어떻게 해야할지 고민하는 개발자분들께 코어 자바스크립트를 추천드립니다.

1-1 데이터 타입의 종류

① 기본형(Primitive type)

특징 : 할당이나 연산 시 복제, 불변성

  • Number
  • String
  • Boolean
  • null
  • undefined
  • symbol (ES6)

② 참조형(Reference type)

특징 : 할당이나 연산 시 참조

  • Array
  • Function
  • Date
  • RegExp(정규표현식)
  • Map, WeakMap (ES6)
  • Set, WeakSet (ES6)

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

  • 컴퓨터는 모든 데이터를 0과 1로 바꿔서 기억합니다.
  • 식별자(identifier) : 어떤 데이터를 식별하는 데 사용하는 이름. 변수명을 의미합니다.
  • 변수(variable) : 변할수 있는 무언가 ➔ 데이터를 의미합니다.

1-3 변수 선언과 데이터 할당

컴퓨터는 변수 선언과 데이터 할당을 서로 다른 메모리 영역에 저장합니다.
예를 들어, var a = abc의 경우 변수 영역에는 이름:a가 저장되고 데이터 영역의 주소를 담습니다. 그리고 실제 데이터인 abc는 데이터 영역에 저장됩니다.

만약 변수 a의 데이터값을 abc에서 abcdef로 재할당할 경우, abc가 담겨있던 기존의 데이터 영역을 abcdef로 바꾸는 것이 아니라 새로운 데이터 영역abcdef를 저장하고 변수 a의 값은 abcdef가 담긴 새로운 데이터영역의 주소를 연결합니다.

1-4 기본형 데이터와 참조형 데이터

변수와 상수를 구분하는 성질은 변경 가능성입니다. 바꿀 수 있으면 변수, 그렇지 않으면 상수입니다. 그러나 많은 개발자들이 상수와 불변값을 같은 개념으로 오해하기도 합니다. 그러나 이 둘은 명확히 다른 개념입니다.

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

참조형 데이터의 경우 '가변값'을 의미하는 것은 참조형 데이터 자체를 변경할 경우가 아니라, 내부의 프로퍼티를 변경할 때만 성립하게 됩니다. 따라서 데이터 자체를 변경하고자 하면

1-5 불변 객체

불변 객체는 React, Vue.js, Angular 등의 라이브러리나 프레임워크뿐만 아니라 함수형 프로그래밍, 디자인 패턴 등에서도 매우 중요한 기초가 되는 개념입니다.
값으로 전달받은 객체에 변경을 가하더라도 원본 객체는 변하지 않아야 하는 경우가 종종 발생하게 됩니다. 이럴 때, 불변 객체가 필요합니다.

불변 객체를 만드는 방법

var user = { 
  name: "Hobs",
  gender: "male"  
}

var changeName = function (user, newName) {
  var newUser = user;
  newUser.name = newName;
  return newUser;
}

var user2 = changeName(user, 'Harry');

if(user !== user2) {
  console.log('유저 정보가 변경되었습니다.')
}
console.log(user.name, user2.name);
console.log(user === user2);

//'Harry' 'Harry'
//true

user 변수와 user2 변수가 서로 같지 않다는 조건이 성립한다면 if문의 console이 출력되겠지만, 실제로는 출력 없이 통과되게 됩니다.
즉, user 객체가 changeName함수로 인해 변하게 된 것입니다.
이는 객체의 불변성을 지키지 않는 것입니다. 따라서 불변성을 지키기 위해선 다음과 같은 코드로 작성해야 되겠습니다.

var user = { 
  name: "Hobs",
  gender: "male"  
}

var changeName = function (user, newName) {
  return {
    name: newName,
    gender: user.gender
  }
}

var user2 = changeName(user, 'Harry');

if(user !== user2) {
  console.log('유저 정보가 변경되었습니다.')
}
console.log(user.name, user2.name);
console.log(user === user2);
//'유저 정보가 변경되었습니다.'
//'Hobs' 'Harry'
//false

이렇게 데이터 자체를 변경하지 않고 내부의 프로퍼티를 변경하게 된다면 불변 객체를 만들 수 있게 됩니다.
그러나 만약 객체에 정보가 많을수록 기존 객체를(프로퍼티(gender)와 같이) 하드코딩으로 입력하는 것은 비효율적입니다. 따라서 이런 방식보다는 모든 프로퍼티를 복사하는 함수를 만드는 편이 좋겠습니다.

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

얕은 복사와 깊은 복사

얕은 복사는 바로 아래 단계의 값만 복사하는 방법이고, 깊은 복사는 내부의 모든 값들을 하나하나 찾아서 전부 복사하는 방법입니다. 위의 copyObj 함수의 경우 얕은 복사만 수행했습니다.

이렇게 되면 중첩된 객체의 경우 참조형 데이터가 저장된 프로퍼티를 복사할 때 그 주솟값만 복사하게 됩니다. 따라서 원본과 사본 모두 동일한 참조형 데이터를 가리키게 되면서 사본을 바꾸면 원본도 바뀌고, 원본을 바꿔도 사본이 같이 바뀌게 되는 것입니다.

그렇기 때문에 어떤 객체를 복사할 때 객체 내부의 모든 값을 복사해서 완전히 새로운 데이터를 만들고자 할 때, 객체의 프로퍼티 중에서 그 값이 기본형 데이터일 경우에는 그대로 복사하면 되겠지만, 참조형 데이터다시 그 내부의 프로퍼티를 복사해야 합니다.

그렇다면 깊은 복사는 어떻게 가능할까요? 객체를 JSON 문법으로 표현된 문자열로 전환했다가 다시 JSON객체로 전환하는 겁니다. (다만 메소드나 getter/setter등과 같이 JSON으로 변경할 수 없는 프로퍼티는 무시하게 됩니다.)

var copyObjectViaJson = function (target) {
  return JSON.parse(JSON.stringify(target))
}

var obj = {
    a:1,
    b: {
      c: null,
      d: [1,2],
      func1: function() {console.log(3)}
      },
    func2: function() {console.log(4)}      
    
}
var obj2 = copyObjectViaJson(obj);

obj2.a = 3;
obj2.b.c = 4;
obj.b.d[1] = 3;

console.log(obj)
console.log(obj2)
//{ a: 1, b: { c: null, d: [ 1, 3 ], func1: ƒ func1() }, func2: ƒ func2()}
//{ a: 3, b: { c: 4, d: [ 1, 2 ] } }

1-6 undefined와 null

JS에는 '없음'을 나타내는 값이 두 가지가 있습니다. 바로 undefinednull입니다.

undefined

사용자가 명시적으로 지정할 수도 있으나 자바스크립트 엔진은 사용자가 값을 지정하지 않았을 때, undefined를 반환합니다. 다음의 세 경우가 이에 해당합니다.

  • 값을 대입하지 않은 변수(데이터 영역의 메모리 주소를 지정하지 않은 식별자)
  • 객체 내부의 존재하지 않는 프로퍼티에 접근
  • return문이 없거나 호출되지 않는 함수의 실행 결과

그러나 값을 대입하지 않는 배열의 경우에는 조금 특이하게 동작합니다.

var arr1 = [];
arr1.length = 3 ;
console.log(arr1);
//output: [ <3 empty items> ]

var arr2 = new Array(3);
console.log(arr2);
//output: [ <3 empty items> ]

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

이와 같이 비어있는 요소undefined를 할당한 요소는 출력 결과부터 다릅니다. 비어있는 요소는 순회와 관련된 많은 배열 메서드들의 순회 대상에서 제외됩니다.

배열 역시 객체이기 때문에 length의 프로퍼티 개수만큼 빈 공간을 확보하고 인덱스를 이름으로 지정하는 것이 아니라, 객체와 마찬가지로 특정 인덱스 값을 지정할 때 비로소 빈 공간을 확보하고, 인덱스를 이름으로 지정하고, 데이터의 주솟값을 저장하는 동작을 하게 됩니다.

null

undefined의 경우 사용자가 직접 부여할 수 있지만, undefined 대신 null을 사용하는 것이 더 바람직합니다. undefined의 경우 아무런 값이 할당되지 않은 변수에 접근했을 때, 자바스크립트 엔진이 반환하는 것으로 받아들이는 것이 컨벤션이라 생각하면 될 것 같습니다.
null의 경우에도 애시당초 이런 용도로 만들어진 데이터 타입입니다.

null의 경우 typeof null이 object입니다. 이는 JS의 자체 버그이기 때문에, 어떤 변수의 값이 null인지 판별하기 위해서는 일치연산자(===)로서 판별해야 합니다. (동등 연산자(==)로 비교할 경우 null과 undefined를 서로 같다고 판단)

위의 글은 온전히 학습 목적을 위해 작성한 글입니다. 위 내용의 모든 지적 재산권,저작권은 코어 자바스크립트 저자에게 있으며, 무단 전재 및 재배포를 금합니다.

profile
내실 있는 프론트엔드 개발자가 되기 위해 오늘도 최선을 다하고 있습니다.

0개의 댓글