[TIL] Javascript 개념

JISU·2021년 12월 11일
0

TIL

목록 보기
20/27

오늘 배운 것

Javascript 개념

원시 값과 객체의 비교

모던 자바스크립트 딥 다이브 Chapter 11

  • 목차

    	1. 데이터 타입
    1. 원시 값
    2. 객체

1. 데이터 타입

Javascript 에는 7가지 데이터 타입이 있다.

* 원시 타입(primitive type)
  - 숫자
  - 문자열
  - boolean
  - null
  - undefined
  - Symbol
* 객체 타입(object/reference type)
  - 객체 타입
  • 원시 타입의 값
    => 변경 불가능한 값(immutable value)
    => 변수에 값을 할당하면 변수(확보된 메모리 공간)에 실제 값이 저장

  • 객체(참조) 타입의 값
    => 값을 할당받은 변수를 다른 변수에 할당하면 값이 복사가 된다.(pass by value)
    => 변경 가능한 값(mutable value)
    => 변수에 할당하면 변수(확보된 메모리 공간)에 참조 값이 저장
    => 변수를 다른 변수에 할당하면 원복의 참조 값이 복사된다.(pass by reference)

2. 원시 값

1) 변경 불가능한 값

원시 값: 원시 타입(primitive type)의 값
  • 원시 값은 변경 불가능한 값이다. (read only)

그런데, 항상 변수에다가 맨날 할당해서 값 변경했었지 않은가?

여기서 말하는 변경 불가능하다는 것은 변수가 아니라 값 자체이다.

변수 -> 값을 저장하기 위해 확보된 메모리 공간을 지칭하는 말
값 -> 변수에 저장된 데이터.

그러니까, 우리는 변수의 값을 변경한 것이 아니라 재할당을 통해서 변수의 값을 교체해버린 것이다.

상수는 재할당이 금지된 변수이다.

// const 키워드를 사용해 선언한 변수는 재할당이 금지된다. 상수는 재할당이 금지된 변수일 뿐이다.
const o = {};

// const 키워드를 사용해 선언한 변수에 할당한 원시값(상수)은 변경할 수 없다.
// 하지만 const 키워드를 사용해 선언한 변수에 할당한 객체는 변경할 수 있다.
o.a = 1;
console.log(o); // {a: 1}
  • 그래서 재할당이랑 값 자체를 변경하는 것이랑 무엇이 다르냐?
    변수에 값을 할당했다가 새로운 원시 값을 재할당하면 새로운 메모리 공간을 확보하고 재할당한 원시값을 저장을 한 후에 변수가 이제 새로운 메모리 위치를 가리킬 수 있도록 하는 것이다.

그러니까, 값 변경이 가능했다면 새로운 메모리 공간의 확보 없이 그 위치에서 값만 변경하면 되나,
immutable 하다면 메모리 공간이 새로 확보가 되고 값이 그 안에 들어가면서 바뀐 위치를 변수가 참조할 수 있도록 하는 것이다. 이러한 특성을 불변성이라고 한다.

2) 문자열과 불변성

자바스크립트에서는 문자열 타입을 제공한다.
문자열 타입 또한 원시 값으로 변경 불가능하다.

ex) 문자열 타입의 사용

var str = 'string';

// 문자열은 유사 배열이므로 배열과 유사하게 인덱스를 사용해 각 문자에 접근할 수 있다.
// 하지만 문자열은 원시값이므로 변경할 수 없다. 이때 에러가 발생하지 않는다.
str[0] = 'S';

console.log(str); // string

문자열은 유사 배열 객체이다. 이터러블하기 때문에 배열과 유사하게 각 문자(요소)에 접근할 수 있다.

유사 배열 객체: 배열 처럼 인덱스로 프로퍼티 값에 접근 가능
length 프로퍼티를 갖는다.
문자열은 원시 값은데 배열(객체)이다..?
원시 값을 객체처럼 사용하려면 원시 값을 감싸는 래퍼 객체로 자동 변환된다.

그러나, 값은 변경이 불가능하므로 일부 문자를 변경해도 반영되지 않는다.

3) 값에 의한 전달

원시 값을 갖는 변수를 다른 변수에 할당하면 원시 값이 복사되어 전달된다.
이것을 값에 의한 전달이라고 한다.

var score = 80;

// copy 변수에는 score 변수의 값 80이 복사되어 할당된다.
var copy = score;

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

주의! 각 변수안에 들어있는 원시 값은 같지만, 서로 다른 메모리 공간에 저장된 별개의 값이기 때문에 각자 변경되어도 서로의 변수 값에는 어떠한 영향도 주지 않는다.

값에 의한 전달 또한 값을 전달하는 것이 아니라 메모리 주소를 전달한다.
전달된 메모리 주소를 통해 메모리 공간에 접근하면 값을 참조할 수 있다.
(이 값을 복사해라기 보다 여기 주소 줄테니까 거기에 있는 값을 복사해)

3. 객체

프로퍼티의 개수가 정해져 있지 않고, 동적으로 추가/삭제할 수 있다.
객체는 확보해야할 메모리 공간의 크기를 사전에 정해둘 수 없다.
객체 관리 방식은 브라우저 제조사마다 다를 수 있다.

V8 자바스크립트 엔진에서는 프로퍼티에 접근하기 위해 동적 탐색 대신
"히든 클래스 방식"을 사용해 객체 프로퍼티에 접근하는 성능을 높인다.

1) 변경 가능한 값

  • 객체(참조) 타입의 값인 객체는 변경 가능한 값(mutable value)이다.

변수에 객체를 할당하면 값을 변수에 넣는 것이 아니라 메모리 주소를 넣는다.
메모리 주소에 가보면 생성된 객체가 저장되어 있다.
메모리 주소를 참조 값(reference value)라고 부른다.

따라서 변수는 객체 값을 갖는다 라고 표현하기 보다 변수는 객체를 참조하고 있다/가리키고 있다.라고 표현한다.

객체는 변경 가능한 값이기 때문에 변수에 재할당없이 객체를 그 메모리 위치에서 직접 변경할 수 있다.

  • 얉은 복사 / 깊은 복사
    객체는 여러 개의 식별자가 하나의 객체를 공유할 수 있다.
    그러니까, 서로 다른 변수인데 참조 값이 같아서 하나의 객체를 같이 가리킬 수 있다는 것이다.

    얉은 복사: 객체를 프로퍼티 값으로 갖는 객체의 경우 한 단계까지만 복사
    깊은 복사: 객체에 중첩되어 있는 객체까지 모두 복사

ex) 얕은 복사와 깊은 복사의 비교

const o = { x: { y: 1 } };

// 얕은 복사
const c1 = { ...o }; // 35장 "스프레드 문법" 참고
console.log(c1 === o); // false
console.log(c1.x === o.x); // true
// c1의 x 프로퍼티는 o 객체의 x 프로퍼티가 가리키는 참조 값을 받아왔기 때문에 같은 것이다.

// lodash의 cloneDeep을 사용한 깊은 복사
// "npm install lodash"로 lodash를 설치한 후, Node.js 환경에서 실행
const _ = require('lodash');
// 깊은 복사
const c2 = _.cloneDeep(o);
console.log(c2 === o); // false
console.log(c2.x === o.x); // false
// 참조 값이 아니라 안에 들어있는 객체 자체를 복사한 것이기 때문에 서로 다른 것이다.
// 그러니까 c2.x가 가리키는 객체의 메모리상 위치와
// o.x가 가리키는 객체의 메모리상 위치가 다른 것이다.
// 안에 내용은 같을 지라도..

얕은 복사와 깊은 복사는 둘다 원본 객체와 다른 객체이다.

2) 참조에 의한 전달
여러 개의 식별자가 하나의 객체를 공유할 수 있기 때문에 발생하는 부작용들이 있다.

객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사되어 전달된다. 이것을 참조에 의한 전달이라고 한다.

각 변수들이 위치한 메모리 주소는 다르지만, 그 변수들이 가지고 있는 참조 값은 같다.
따라서, 둘 중 하나에서 객체를 변경하면 다른 한 쪽도 영향을 받게 된다.

그런데 사실 변수에 다른 변수를 할당할 때,
변수(메모리 공간)에 가지고 있는 값을 복사하고 전달하는 것은 같다.

다만, 할당하려고 하는 것이 객체일 때 메모리 공간 안에 들어있는 값이 참조 값이기 때문에 영향이 가는 것 뿐이다.

따라서 자바스크립트에서는 참조에 의한 전달은 없고 값에 의한 전달만이 존재한다고 볼 수 있다.

profile
블로그 이전

0개의 댓글