study: javascript | 숨참고 deep dive (11) 원시 값과 객체의 비교 - 221201

Lumpen·2022년 11월 30일
0

Study

목록 보기
14/92

자바스크립트는 크게 원시 타입과 객체 타입 두 가지 타입으로 구분할 수 있다

원시 값은 변경 불가능한 값
객체 값은 변경 가능한 값이다

원시 값을 변수에 할당하면 변수(메모리 공간) 에는 실제 값이 저장된다
객체를 변수에 할당하면 참조 값이 저장된다

원시 값을 갖는 변수를 다른 변수에 할당하면 원시 값이 복사되어 전달된다
이를 pass by value 라고 한다
객체 값을 다른 변수에 할당하면 참조 값이 복사되어 전달된다
이를 pass by reference 라고 한다

1. 원시 값

한번 생성된 원시 값은 읽기 전용으로 변경할 수 없다
이러한 특성을 불변성이라고 한다
원시 값은 불변성을 갖기 때문에 값을 할당한 변수는 재할당으로만 값을 변경할 수 있게 된다
변수가 참조하던 메모리 주소를 변경하는 것이다

1-2. 문자열과 불변성

원시 값을 저장하려면 미리 타입에 따른 메모리 공간의 크기를 결정해야 한다
원시 타입별 메모리 공간의 크기가 미리 정해져 있다
ECMAScript 사양에 문자열: 2바이트, 숫자: 8바이트 만이 정의되어 있다

문자열은 원시값이지만 다른 원시값 과는 다른 특징을 갖는다
문자열은 0개 이상의 문자로 이뤄진 집합을 말하며 1개의 문자는 2바이트 메모리 공간에 저장된다
따라서 문자열은 몇 개의 문자로 이루어졌는지에 따라 메모리 공간의 크기가 결정된다
숫자 값은 1이든 100000이든 동일한 8 바이트만 사용한다

이와 같은 이유로 C 에서는 문자 타입은 지원하지만 문자열 타입을 지원하지 않는다
C 에서는 문자열을 문자 배열로 처리하고 자바에서는 문자열을 String 객체로 처리한다
자바스크립트는 개발자의 편의를 위해 문자열을 원시 타입으로 제공한다
문자열도 원시타입이기 때문에 변경 불가능한 값이다

문자열은 유사 배열 객체이면서 iterable 이므로 배열과 유사하게 각 문자에 접근 가능하다

유사 배열 객체

유사 배열 객체란 배열처럼 인덱스로 프로퍼티 값에 접근할 수 있고
length 프로퍼티를 갖는 객체를 말한다
반복문으로 순회할 수도 있다

원시 값을 감싸는 래퍼 객체로 변환되면서 원시 값을 객체 처럼 사용할 수 있다

문자열은 읽기 전용 값으로 변경 불가능하다

1-3. 값에 의한 전달

원시 타입을 값으로 갖는 변수를 다른 변수에 할당하면
값을 갖는 변수는 값으로 평가되므로 해당 값이 전달된다
이 때 값을 전달하기 위해 새로운 메모리 영역에 값을 생성 후
전달 받은 변수가 참조하게 된다

이것을 값에 의한 전달이라고 한다
값은 같지만 별도의 메모리 공간에 복사한 값을 저장 후 참조

ECMAScript 에는 메모리 공간을 어떻게 관리해야 하는지 명확하게 전달되어 있지 않기 때문에
엔진 제조사에 따라 동작 방식이 조금씩 다를 수 있다

값에 의한 전달, 참조에 의한 전달은 공유에 의한 전달로 표현되기도 한다

엄격하게 표현하면 값에 의한 전달은 잘못되었다
변수가 기억하는 것은 해당 변수가 참조하고있는 메모리 영역의 주소이기 때문이다

2. 객체

객체는 프로퍼티 개수가 정해져있지 않으며, 동적으로 추가되고 삭제될 수 있다
프로퍼티 값에도 제약이 없다
따라서 객체는 확보해야 할 메모리 공간의 크기를 사전에 정해둘 수 없다

자바스크립트 객체의 관리 방식

자바스크립트 객체는 키를 인덱스로 사용하는 해시 테이블 (연관 배열) 이라고 생각할 수 있다
대부분의 자바스크립트 엔진은 해시 테이블과 유사하지만 높은 성능을 위해
해시 테이블 보다 나은 방법으로 구현한다

C++이나 자바의 경우에는 클래스 기반 객체 지향으로 사전에 정의된 클래스를 기반으로 객체(인스턴스) 를 생성한다
이는 객체를 생성하기 이전 프로퍼티와 메소드가 정해져 있다
객체 생성 이후에는 프로퍼티를 삭제하거나 추가할 수 없다

자바스크립트는 클래스 없이 객체를 생성할 수 있으며 
객체가 생성된 이후에도 동적으로 프로퍼티와 메소드를 추가할 수 있다
사용하기에는 편리하지만 이론적으로 프로퍼티 접근에 비용이 더 많이 든다
V8 자바스크립트 엔진에서는 프로퍼티에 접근하기 위해 동적 탐색 대신 
히든 클래스 방식을 사용하여 C++ 객체 만큼의 성능을 보장한다
히든 클래스는 자바와 같이 고정된 객체 레이아웃(클래스)과 유사하게 동작한다

2-1. 변경 가능한 값

참조 타입의 값, 객체는 변경 가능한 값이다

원시 값을 할당한 변수가 기억하는 메모리 주소를 통해
메모리 공간에 접근하면 원시 값에 접근할 수 있다

말이 어려운데 그냥 변수가 기억하는 메모리 공간에 다른 공간에 있는 객체의 주소를 저장하는 것주소를 통해 메모리 공간에 접근하면 참조 값에 접근할 수 있다
참조 값은 메모리 공간의 주소 그 자체다

객체를 할당한 변수를 참조하면 원시 값과 다르게
메모리 저장되어 있는 참조 값을 공유하게되고 참조 값을 통해 실제 객체에 접근한다

원시 값은 변경 불가능한 값으로 원시 값을 갖는 변수의 값을 변경하려면
재할당 외에는 방법이 없다
하지만 객체는 변경 가능한 값이다
객체를 할당한 변수는 재할당 없이 객체를 직접 변경할 수 있다
재할당을 하지 않으므로 변수의 참조 값은 변경되지 않는다

객체를 생성하고 관리하는 방식은 복잡하고 비용이 많이 드는 작업이다
객체를 원시 값 처럼 다룬다면 신뢰성은 높아지겠지만 비용이 너무 커질 수 있다
객체는 크기가 매우 클 수 있고 어떤 값이든 들어갈 수 있기 때문에
따라서 메모리를 효율적으로 사용하기 위해 객체는 참조 값을 공유한다

원시 값과는 다르게 여러개의 식별자가 하나의 객체를 공유할 수 있다는 점에서
부작용이 생길 수 있다

얕은 복사와 깊은 복사

얕은 복사는 객체의 참조 값만 복사하는 것이고
깊은 복사는 객체에 중첩된 모든 값을 복사하는 것이다

2-2. 참조에 의한 전달

여러개의 식별자가 하나의 객체를 공유할 수 있고 부작용이 따른다

객체를 담고있는 변수를 다른 변수에 할당하면
객체의 값을 전달하는 것이 아닌 객체를 참조하는 객체 메모리공간의 주소를 전달한다
두 식별자가 하나의 객체를 공유하게 된다
한 쪽 변수에서 객체를 수정하면 다른 쪽에서도 같은 객체를 참조하기 때문에 함께 수정된다

값에 의한 전달과 참조에 의한 전달은 사실 같은 방식이다
단지 전달할 대상이 원시 값이냐 객체냐에 따라 자바스크립트의 메모리 관리 방식이 다를 뿐이다
따라서 자바스크립트의 전달 방식은 하나만 존재하는 것이다
이 것을 공유에 의한 전달이라고 표현도 하지만 썩 와닿지 않는다
ECMAScript 에서는 위 세가지 용어 중 어떠한 것도 정의되어 있지 않다

자바스크립트에는 포인터 개념이 없기 때문에 참조에 의한 전달이라는 표현도 다른 언어와 다르다

profile
떠돌이 생활을 하는. 실업자는 아니지만, 부랑 생활을 하는

0개의 댓글