Skip to content

Latest commit

 

History

History
403 lines (288 loc) · 14.3 KB

데이터 타입.md

File metadata and controls

403 lines (288 loc) · 14.3 KB

데이터 타입

데이터 타입의 종류

RubberDuck

  • 기본형 : number, string, boolean, null, undefined, Symbol

  • 참조형 : Object

    • Map, WeakMap, Set, WeakSet, Array, Function, 날짜(Date), 정규표현식(RegExp)
  • 기본형과 참조형의 차이

    • 기본형 : 값이 담긴 주솟값을 바로 복제한다.
      • 기본형은 불변성을 뛴다.
    • 참조형 : 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복제한다.
  • 식별자와 변수

    • 변수: 변할 수 있는 데이터 (숫자, 문자열, 객체, 배열 등)
    • 식별자: 어떤 데이터를 식별하는데 사용하는 이름 (=변수명)

변수 선언과 데이터 할당

변수 선언

var a; // 변수 a 선언
  • 변수 선언 : 변경 가능한 데이터가 담길 수 있는 공간

데이터 할당

a = 'abc'; // 변수 a에 데이터 할당

var a = 'abc'; // 변수 선언과 할당을 한 문장으로 표현

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

불변값

  • 변수와 상수는  변경 가능성으로 구분함
    • 바꿀 수 있으면 ⇒ 변수
    • 바꿀 수 없으면 ⇒ 상수
    • 불변값과 상수를 구분할 때의 변경 가능성의 대상은 ‘데이터 영역’ 메모리이다.
  • 불변성 : 한 번 만든 값을 바꿀 수 없고, 변경은 새로 만드는 동작을 통해서 만 이뤄진다.

기본형의 특징

  • 기본형은 불변성을 띈다.
  • 숫자, 문자열, boolean, null, undefined, Symbol은 모두 불변 값이다.
    • 즉, 기본형은 불변 값이다.

참조형의 특징

  • 참조형은 가변값이다.

가변값

참조형 데이터의 할당 예시)

var obj1 = {
  a: 1,
  b: 'bbb'
};

참조형 데이터의 프로퍼티 재할당 예시)

var obj1 = {
  a : 1,
  b : 'bbb',
};
obj1.a =2;
console.log(obj1) // { a: 2, b: 'bbb' }

중첩된 참조형 데이터(객체)의 프로퍼티 할당 예시)

var obj = {
  x: 3,
  arr: [3, 4, 5] 
};
  • 중첩 객체 : 참조형 데이터의 프로퍼티에 다시 참조형 데이터를 할당하는 경우

변수 복사 비교

  • 기본형 데이터 vs 참조형 데이터의 차이를 확인해보자

변수 복사 예시)

var a = 10; // 기본형 데이터
var b = a;

var obj1 = {c: 10, d: 'ddd'}; // 참조형 데이터
var obj2 = obj1;
  • 변수 복사하는 과정은 기본형 데이터와 참조형 데이터 모두 같은 주소를 바라보게 되는 점에서 동일하다.

변수 복사 이후 값 변경 결과 비교 - 객체의 프로퍼티 변경 시 )

var a = 10; // 기본형 데이터
var b = a;
var obj1 = {c: 10, d: 'ddd'}; // 참조형 데이터
var obj2 = obj1;

b = 15;
obj2.c = 20;

b // 15
obj1 // {c: 20, d: 'ddd'}
obj2 // {c: 20, d: 'ddd'}
  • 기본형 데이터 : 값이 변경되고,
  • 참조형 데이터 : 값이 변경 되지 않음
    • 즉, 기본형 데이터 : a와 b는 서로 다른 주소를 바라보게 됐고,
    • 참조형 데이터 : 변수 obj1와 obj2는 여전히 같은 객체를 바라보고 있는 상태이다.
📌 대부분 js책에서는 ‘기본형은 값을 복사하고 참조형은 주솟값을 복사한다’라고 설명하고 있지만, 사실은 어떤 데이터 타입이든 변수에 할당하기 위해서는 주솟값을 복사해야 하기 때문에 자바스크립트의 모든 데이터 타입은 참조형 데이터일 수 밖에 없다.

변수 복사 이후 값 변경 결과 비교 (2) 예시)

var a = 10; // 기본형 데이터
var b = a;
var obj1 = {c: 10, d: 'ddd'}; // 참조형 데이터
var obj2 = obj1;

b = 15;
obj2.c = 20;

a === b // false
obj1 === obj2 // true

변수 복사 이후 값 변경 결과 비교 (3) - 객체 자체를 변경했을 때 예시)

var a = 10; // 기본형 데이터
var b = a;
var obj1 = {c: 10, d: 'ddd'}; // 참조형 데이터
var obj2 = obj1;

b = 15;
obj2.c = {c: 20, d: 'ddd'};

obj2 // {c: {…}, d: 'ddd'}

image

RubberDuck

  • 객체 자체를 변경했을 때 객체에 대한 변경임에도 값이 달라짐

불변객체

불변 객체를 만드는 간단한 방법

  • 불변 객체는 React, Vue 등의 라이브러리나 프레임워크, 디자인 패턴 등에서도 매우 중요한 기초 개념임
    • 참조형 데이터의 ‘가변’은 데이터 자체가 아닌 내부 프로퍼티를 변경할 때만 성립함
  • 데이터 자체를 변경하고자(새로운 데이터를 할당)하면 기본형 데이터와 기존 데이터는 변하지 않는다.
    • 내부 프로퍼티를 변경할 필요가 있을 때마다 매번 새로운 객체를 만들어 재할당하기로 규칙을 정하거나 자동으로 새로운 객체를 만드는 도구 활용하면 불변성 확보 가능함

기존 정보를 복사해서 새로운 객체를 반환하는 함수(얕은 복사) 예시)

var user = {
  name: 'Jaenam',
  gender: 'male'
};

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

var user2 = copyObject(user);
user2.name = 'Jung';

if (user1= user2) {
  console.log('유저 정보가 변경돠었습니다.'); // 결과 : 유저 정보가 변경돠었습니다.
}

console.log(user.name, user2.name); // Jaenam Jung
console.log(user == user2); // false
  • copyObject는 for in 문법을 이용해 result 객체에 target 객체의 프로퍼티들을 복사하는 함수이다.

얕은 복사와 깊은 복사

얕은 복사 : 참조형 타입의 값이 바로 아래 단계의 값만 복사하는 방법

  • 중첩된 객체에서 참조형 데이터가 저장된 프로퍼티를 복사할 때 그 주소값만 복사함
  • 원본과 사본이 동일한 참조형 데이터 주소를 가리키므로 사본을 바꾸면 원본도 바뀜

깊은 복사 : 내부의 모든 값들을 하나하나 찾아서 전부 복사하는 방법

  • 중첩된 객체에서 프로퍼티 내부의 모든 값들까지 전부 복사함. 재귀로 구현 가능함

얕은 복사 예시)

var obj1 = {
  a: 1,
  b: {
    c: 2,
  },
};
var obj2 = { ...obj1 };
console.log(obj1 === obj2); // false
console.log(obj1.b === obj2.b); // true
  • 두 개의 객체는 다른 주소를 가지고 있지만, 객체 안 프로퍼티는 동일한 주소를 가지고 있다. 쉽게 말하면 {} 는 새로 생성된 객체이며, 새로운 주소를 갖게 되었고 spread 연산자로 풀어진 프로퍼티들은 처음 선언된 obj1의 프로퍼티들이 사용되었다.
  • 얕은 복사를 만드는 방법은 위에 사용한 spread 연산자를 통해 만들 수도 있고 다른 방법으로도 만들 수 있다. spread 연산자는 객체 뿐 아니라 배열에서도 동일하게 동작한다.

중첩된 객체에 대한 얕은 복사 예시)

var user = {
  name: 'Jaenam',
  urls: {
    portfolio: 'https://github.com/abc',
    blog: 'http://blog.com/abc',
    facebook: 'http://facebook.com/abc'
  }
};
var user2 = copyObject(user);

 **user2.name = 'Jung';**
console.log(user.name === user2.name); // false

 **user.urls.portfolio = 'http://portfolio.com';**
console.log(user.urls.portfolio === user2.urls.portfolio); // true

 **user.urls.blog = '';**
console.log(user.urls.blog === user2.urls.blog); // true
  • ①사본인 user2의 name 프로퍼티를 바꿔도 user의 name 프로퍼티는 바뀌지 않는다.
  • ②③ 두 변수는 원본과 사본 중 어느 쪽을 바꾸더라도 다른 한쪽의 값도 함께 바뀐 것을 확인할 수 있다.
    • 즉, user 객체에 직접 속한 프로퍼티에 대해서는 복사해서 완전히 새로운 데이터가 만들어짐
  • 반면에 한 단계 더 들어간 urls의 내부 프로퍼티들은 **기존 데이터를 그대로 참조하는 것”**이다.
    • 이런 현상이 발생하지 않게 하려면 user.urls 프로퍼티에 대해서도 불변 객체로 만들어야 한다.

기본형 타입의 깊은 복사 예시 1)

var a = 10;
var b = a;
console.log(a); // 10
console.log(b); // 10
  • 자바스크립트에서는 할당 연산자(=)를 사용해 쉽게 복사를 할 수 있다.
  • b에 10을 직접 할당해주지 않아도 a를 할당 했기 때문에 10이라는 결과값이 나왔다. 하지만, 정확하게 말하자면 할당 연산자(=)는 객체를 복사해서 값에 집어 넣는 것이 아니다. 단지 a가 가지고 있는 주소를 b에게 주어 b도 그 대상을 바라보게 만든 것이다.
  • 기본형 타입은 ‘불변값’ 이라고 했다. 기본형 타입의 값을 재할당 할 때는 기존 값을 변경하는 것이 아닌 새로 만들어 주소 값을 준다는 의미였다. 따라서, a와 b는 메모리 공간에 생성된 10의 주소값을 가지고 있다.

기본형 타입의 깊은 복사 예시 2)

var a = 10;
var b = 10;
console.log(a === b); // true
var c = 20;
var d = c;
console.log(c === d); // true

d = 30;
console.log(c); // 20
console.log(d); // 30
console.log(c === d); // false
  • 기본형 타입의 값을 바라보는 주소값이 동일하기 때문에 a와 b는 각각 값을 할당 받았지만 동일하다고 판단한다.
  • d도 마찬가지로 c의 주소를 넘겨받았기 때문에 동일하다고 판단한다.
  • c의 주소를 넘겨 받은 d에 30을 재할당 했다.
  • c와 d는 다른 값을 바라보고 있다.
    • 내부의 값은 없지만 복사했을 때, 서로의 주소가 달라졌다. 기본형 타입의 깊은 복사다. 서로에게 영향을 주지 않는다.

참조형 타입의 깊은 복사 )

var obj1 = {
  a: 10,
  b: 'abc',
};
var obj2 = obj1;
console.log(obj1 === obj2); // true

obj2.a = 20;
console.log(obj1); // {a: 20, b: 'abc'}
console.log(obj2); // {a: 20, b: 'abc'}
console.log(obj1 === obj2); // true
  • obj1과 obj2가 가지고 있는 주소 값이 동일하기 때문에 true가 나왔다.
  • obj2의 a프로퍼티의 값을 20으로 재할당했다.
  • obj1, obj2의 값의 a 프로퍼티 모두 20으로 변경되었다.
  • 여전히 obj1과 obj2가 가지고 있는 주소 값이 동일하다.

obj2의 ’프로퍼티‘를 변경시켰기 때문에 이러한 결과가 나옴. 프로퍼티 a가 바라보고 있는 주소 자체는 변경되었지만 obj1, obj2가 프로퍼티 ‘그룹’을 바라보는 주소자체는 변경되지 않은 것이다. 이렇게 객체 자체의 참조 값을 할당하면, 깊은 복사가 일어나지 않는다.

중첩된 객체에 대한 깊은 복사 예시)

var user = {
  name: 'Jaenam',
  urls: {
    portfolio: 'https://github.com/abc',
    blog: 'http://blog.com/abc',
    facebook: 'http://facebook.com/abc'
  }
};
var user2 = copyObject(user);
① user2.urls = copyObject(user.urls);

user.urls.portfolio = 'http://portfolio.com';
② console.log(user.urls.portfolio === user2.urls.portfolio); 
//false

user2.urls.blog = '';
③ console.log(user.urls.blog === user2.urls.blog); // false
  • ① urls 프로퍼티에 copyObject 함수를 실행하여 urls 프로퍼티의 내부까지 복사해서 새로운 데이터가 만들어졌으므로 ②③ 값이 서로 다르다는 결과를 얻었다.
  • 어떤 객체를 복사할 때 객체 내부의 모든 값을 복사해서 완전히 새로운 데이터를 만들고자 할 때
    • 객체의 프로퍼티 중에서 그 값이 기본형 데이터일 경우에는 그대로 복사하면 되지만
    • 참조형 데이터의 경우다시 그 내부의 프로퍼티를을 복사해야 한다.

얕은 복사는 한 단계까지만 복사하고, 깊은 복사는 객체에 중첩된 객체까지 모두 복사한다. 얕은 복사와 깊은 복사 모두 복사한 대상에 대해서 새로운 객체를 생성하여 기존 객체에는 영향을 주지 않는다. 하지만 얕은 복사와 깊은 복사는 어느 수준까지 복사하느냐의 차이를 가진다. 얕은 복사를 하면 아래 단계만 복사하기 때문에 중첩된 객체에 대해서는 서로 영향을 주고, 깊은 복사는 중첩된 객체 역시 별개의 값으로서 서로 영향을 주지 않는다.


undefined와 null

  • undefined와 null은 자바스크립트에서 모두 ‘없음'을 나타낸다. 하지만 미세하게 차이점이 있다.

undefined

  • 자바스크립트 엔진은 사용자가 어떤 값을 지정할 것이라고 예상되는 상황임에도 실제로 그렇게 하지 않았을 때 undefined를 반환한다.
    • 값을 대입하지 않은 변수. 즉, 데이터 영역의 메모리 주소를 지정하지 않은 식별자에 접근할 때
    • 객체 내부의 존재하지 않는 프로퍼티에 접근하려고 할 때
    • return 문이 없거나 호출되지 않는 함수의 실행 결과

null

  • null은 ‘비어있음'을 명시적으로 나타내고 싶을 때 사용한다.
  • typeof null은 object라고 반환되는데, 이는 자바스크립트 자체 버그이다. 따라서 변수의 값이 null인지 확인하려면 일치 연산자로 확인을 해줘야 한다.

undefined와 null을 구분하기 위해서는 동등 연산자 대신, 일치 연산자(===)를 사용해야 한다.

var n = null;
console.log(typeof n); // object

console.log(n == undefined);  // true
console.log(n == null);  // true

console.log(n === undefined);  // false
console.log(n === null);  // true

정리

  • 변수: 변경 가능한 데이터가 담길 수 있는 공간
  • 식별자: 그 변수의 이름을 말함 (=변수명)
  • undefined : 어떤 변수에 값이 존재하지 않을 경우를 의미함
  • null : 사용자가 명시적으로 ‘없음’을 표현하기 위해 대입한 값이다.

참고

정재남, 코어 자바스크립트

JavaScript의 얕은 복사와 깊은 복사, Pozafly, https://pozafly.github.io/javascript/shallo-copy-and-deep-copy/