JS에서는 기본 데이터 타입인 number
, string
, boolean
, null
, undefined
를 제외한 모든 것들이 전부 '객체'이다. 배열은 물론이고 함수조차 사실은 객체로 표현되며, 당연히 메모리에도 객체의 형태로 올라간다.
number
, string
, boolean
데이터타입은 객체가 아닌 하나의 값의 형태로 메모리에 올라가지만 객체처럼 다룰 수 있다. (이에 대해서는 나중에 자세히 다룰 예정)
참조된다는 말은 맞지만, 아래 내용은 어느정도 추측을 포함한다🤷♀️
이해를 돕기 위해 다음의 코드를 먼저 보자
var apple = {color: 'red'}
위의 코드에서 사과의 정보를 담은 객체를 만들어서 apple이라는 변수에 할당했다. 이 과정에서 JS엔진은 apple 변수를 위한 메모리에 객체를 저장하지 않는다.
실제로는 객체를 먼저 생성해 메모리에 올리고, 그 주소를 apple변수에 할당한다. 마치 C언어의 포인터같다. 이후 apple객체를 사용할 때 내부적으로는 apple이 가리키는 주소에 있는 객체에 접근하는 것이다.
var apple = {color: 'red'}
var apple2 = apple
appel2.color = 'yellow'
따라서 위의 코드를 실행하면 apple2의 color뿐만 아니라 apple의 color까지 yellow로 바뀐다.
var apple2 = apple
이라는 코드에서 apple2변수에 apple이라는 메모리 주소
를 할당하기 때문에, 두 변수는 하나의 객체를 가리키고 있는 탓이다.
또한 함수의 매개변수로 객체를 넘길 때에도 객체의 값이 아닌 주소가 넘어간다.
이러한 특성 때문에 얕은 복사
, 깊은 복사
라는 개념이 나온 듯하다.
위의 코드처럼 apple2에 apple을 할당하면 실제로 객체가 두 개가 된 것이 아닌, 한 객체를 가리키는 변수가 두 개가 된 것이다. 이러한 복사를 얕은 복사
라고 하며, 메모리상에도 똑같은 객체를 새로 올려서 객체가 2개가 되는 복사(대부분의 사람들이 의도한 그 복사)를 깊은 복사
라고 한다.
객체를 깊은 복사 하는 방법엔 여러 가지가 있지만 그 중 하나로 객체->문자열로 변환 후 다시 문자열->객체로 변환하여 새 변수에 할당하는 방법이 있다.
var apple = {color: 'red'}
var apple2 = JSON.parse(JSON.stringify(apple))
이러한 방식으로 만든 apple2는 color 속성을 변경해도 apple객체에 영향을 주지 않는다.
우선 배열도 내부적으로는 일종의 객체이기 때문에 위와 같은 방법을 써서 복사할 수 있다.
그렇지만 그 방법은 거의 쓰이지 않고, 보통은 배열의 표준 메서드인 slice()
를 이용한다.
Array.prototype.slice
메서드는 원본 배열의 원하는 부분을 칼로 자르듯 자른 새로운 배열을 반환한다. 매개변수로 시작점만 넘겨주거나 시작점과 끝지점을 넘겨줄 수도 있지만 아무것도 안 넘겨줄 수도 있다. 이 경우엔 똑같은 배열 하나 새로 만들어준다.
var fruits = ['apple', 'grape']
var fruits2 = fruits.slice()