다시 한 번 톺아보는 JS문법.
참조 하면 주소 참조가 떠오르는데, 데이터 저장 시 주소값을 저장하는 객체나 배열을 생각할 수 있다.
이 때 알게 모르게 열ㅡ일하고 있던 친구가 있는데, 그게 사실은 컴퓨터 뜯으면 있는 시금치 라는 거다.
아 시금치
생물 시금치 말고 이런 시금치 되시겠다.
이 친구가 바로 메모리란 건데, 누구든 컴퓨터에 하나씩 (?) 들어있는 RAM을 생각하면 좋다.
변수 선언, 데이터 할당, 메모리, 주소값 등등
개발을 처음 시작하다 보면 배울 게 참 많았는데, 그 중 메모리에 대해 잠시 짚어보자.
메모리(주기억장치)는 RAM과 같은 저장소를 의미하고, RAM이란 Random Access Memory의 약어라고 할 수 있음.
컴퓨터 메모리는 모든 컴퓨팅 시스템의 필수적인 부분으로, 빠른 액세스 또는 검색을 위해 데이터가 임시 또는 영구적으로 유지되는 중개 스토리지 공간의 역할을 한다.
(출처: 퓨어스토리지)
우리가 변수에 값을 할당하면서, 그 값들이 다 어디에 저장되어 있는지는 잘 모르지만.. 컴퓨터 내부의 프로세스는
간단히 생각했을 때
이건데, 이제 객체를 선언한다거나 배열을 선언하게 되면 저기서 좀 달라지는 거라고 할 수 있겠지.
위에서도 각각의 요소가 저장되는 구역이 다르다고 슬쩍 남겨보았는데, 그거의 연장선이다.
만일 객체를 선언한다 치면,
키값은 키 공간에 주르륵 저장하고,
각 데이터도 데이터 공간에 저장하고,
그 데이터의 주소값을 가져와서 키에 달아줌.
복잡시럽지만 무튼...!
배열/객체와 같은 참조형 데이터는 값을 직접 가지지 않고, 해당 값이 저장된 메모리 주소를 가리킨다.
JavaScript - 직접적인 메모리 주소를 다루지 않으나, 내부적으로는 참조형 데이터가 메모리 주소를 참조한다.
자바스크립트에는 두가지 메모리영역(저장영역)이 존재함.
자료구조(?)라 할 수 있는 스택과 힙.
변수 선언, 객체, 값 등을 할당함에 있어서 어딘가에 저장해 둔 값을 가져다 쓰는 것임을 알고 있자.
그 저장 타입이 Stack/Heap이라는 것 까지!
같은 타입의 데이터를 여러 개 가지고 있는 자료형
index 시작 숫자가 0부터인 이유!
주소값을 통하여 참조하는 메모리의 시작점을 0이라고 표현하기 때문이다.
Object는 {}
중괄호로 묶인 친구들.
특징은 늘 key-value
쌍이라는 것.
메모리에 데이터를 어떻게 저장하는지는 위에서 조금 다루었으니 패스해보겠다.
객체나 배열을 Copy하는 일이 더러 있다.
보통 생각하는 코드인 let b = a
와 같이, 기존 a
의 값을 새로운 변수인 b
에 할당하려고 하면, 겉보기엔 "잘 복사됐군!" 생각할 수 있겠다.
하지만 메모리 내부를 들여다 봤을 때는, 해당 값이 저장된 (메모리) 주소가 같다. 그냥 둘이 완전 똑같은 객체(배열)이라는 거다.
그래서 "아~ 원본 a는 그대로 두고, b만 복사해서 수정해야겠다!" 생각하고서 배열/객체를 이렇게 복사해서 수정한다면?
원본도 같이 수정되어버리는 Magic ⭐️
이런 문제를 해결하면서, 기존의 배열이나 객체를 어떻게 복사할 수 있을까? 의 해답이 깊은 복사.
값은 동일하지만, 비하인드를 들춰보자면 값이 저장된 주소가 다르다:)
그래서 깊은 복사로 생성한 배열/객체는 아무리 수정을 해도 원본은 그대로 유지된단 점.
깊은 복사는 immutable(비변경)이 필요할 때 사용하게 됨.
얕은복사를 하게 되면, 원본주소값이 그대로 불려오므로 2개 객체가 같이 변경되거든요...
재귀적 방법 : 재귀함수 이용
JSON.parse / JSON.stringify
: string화 시켜서 새로운 배열로 만들기
parsing = 새로운 다른 자료구조를 만들기
let deepCopy = JSON.parse(JSON.stringify(original));
잠깐, JSON 방식의 한계점
object 안의 메소드/함수 등은 복사가 되지 않는다.
lodash / cloneDeep 메소드를 이용한 복사
structuredClon() 전역 함수
: JS 내장 깊은복사 메소드
메소드와 함수의 차이?
함수는 독립적으로 사용가능하지만, 메소드는 종속적으로 사용하게 된다.
많이 쓰는 만큼 익숙해질수 있도록!
원본 배열의 수정 여부에 따라서 변경 메소드 (mutable) / 비변경 메소드 (immutable)로 나눈다.
정렬 시의 인자로 콜백함수를 받는데, 그 자리에는 compareFunction을 넣어준다.
numbers.sort((a,b) => a-b);
(UNICODE 기반. 숫자정렬 시엔 compareFn을 넣어주자)
이 중에 실행 속도가 제일 빠른 것은 push/pop.
맨 뒤 인덱스에 접근하는 게, 앞쪽으로 가는 것보다 빠르겠죠?
Stack 생각 중...
start
부터 end
직전의 요소까지 복사해 새로운 배열로 반환key-value
쌍을 배열로 반환