[Javascript] 값에 의한 전달 vs 참조에 의한 전달

Hyuk·2023년 1월 7일
0

예전 개발을 처음 배우고 프로젝트에 착수했을 때의 이야기이다. 그때 당시에 알고리즘 중 이분검색을 공부하고 있던 와중에 다음과 같은 코드를 본 적이 있다.
(알고리즘은 파이썬으로 공부했어서 파이썬 코드이다.)

lt = res = 0
rt = n - 1

그 전의 나는 다음과 같이 ltres 라는 변수를 각각 할당했지만 위의 코드를 보고 한번에 할당시켜서 코드를 줄일 수도 있구나 라는 생각을 했었다.

lt = 0
res = 0
rt = n - 1

그러던 중 프로젝트에서 다음과 같은 코드를 작성한 적이 있다.

let selectBox = valueBox = []

당연히 위의 selectBoxvalueBox는 다른 값을 담는 배열이였고 하는 역할도 달랐다. 공통점은 배열이라는 점일 뿐. 저렇게 코드를 작성하고 실행 시켜보니 의도하던 대로 나오지 않아 당혹스러웠던 적이 있다.
lt = res = 0은 문제없이 잘 되던게 왜 selectBox = valueBox = []는 왜 원하는 대로 동작하지 않을까?

차분히 디버깅을 하던 중 selectBoxvalueBox를 각각 배열을 생성해서 에러를 처리했고 이러는 이유가 궁금해 찾아본 적이 있다.

처음엔 언어의 문제인가 싶기도 했었다. 알고보니 문제는 값에 의한 전달과 참조에 의한 전달의 차이였다. (그 전에 원시 값과 객체의 차이도 있었겠지만)

값에 의한 전달

let lt = res = 0

위의 코드는 res0이라는 값을 할당하고 ltres 변수를 할당했다.

res 변수와 lt 변수가 각각 0이라는 값을 갖는다는 점에서 동일하다. 하지만 각각의 값 0은 다른 메모리 공간에 저장된 별개의 값이다.

다시 말해, res가 가리키는 메모리 주소와 lt가 가리키는 메모리 주소는 다르다는 것이다.

그럼 만약 다음과 같은 코드를 실행한다면 각 변수의 값은 어떻게 될까?

for (let i = 0; i < 2; i++) {
	res += 1
};

console.log(res) // 2
console.log(lt)  // 0

코드에도 나와있지만 res의 값과 lt 값은 달라진다. 답은 아까 말했던 것에 나와있다.
각 변수는 동시에 같은 값을 할당했지만 다른 메모리 주소에서 그 값들을 담고 있던 것이다.
그렇기 때문에 res 변수에 값에 연산을 해도 lt의 값은 달라지지 않는 것이다.

참조에 의한 전달

let selectBox = valueBox = []

위의 코드를 저렇게 작성하고 나서 valueBox의 값을 확인했을 때엔 selectBox에 들어가 있어야 할 값과 valueBox에 있어야 할 값들이 같이 뒤엉켜 있었다.
이유는 selectBoxvalueBox하나의 배열을 공유했기 때문이다.

그렇다면 왜 값에 의한 전달에선 각각 값을 저장하고 참조에 의한 전달은 하나의 값(=객체)을 공유할까?
값에 의한 전달은 원시 값(primitive type)이고, 참조에 의한 전달은 객체 타입 값(object type)이기 때문이다.


원시 값과 객체 타입 값

자바스크립트는 객체 기반 프로그래밍 언어이며, 거의 모든 것이 객체 타입의 값이다. 예외는 원시 값이다.
그렇기 때문에 원시 값을 제외한 모든 것은 객체 타입의 값으로 생각하면 편하다.
원시 값은 숫자, 문자열, Boolean, null 등이 있다.

원시 값은 불변성이라는 특성을 가지지만, 반대로 객체 값은 변경이 가능하다는 특성이 있다.
그말인즉슨 원시 값을 재할당하면 새로운 메모리 공간에 재할당한 값을 저장한 후 변수가 참조하는 메모리 주소를 변경한다.
하지만 객체 값을 재할당하면 새로운 메모리 공간을 확보하지 않고 메모리에 저장되어 있는 참조 값을 통해 실제 객체에 접근해서 값을 재할당한다.


이러한 특성이 곧 값에 의한 전달과 참조에 의한 전달로 이어진다.

원시 값을 전달하면 서로 불변성을 유지해야 하기 때문에 서로 다른 메모리 주소에 별개의 값이 저장되는 것이고
참조에 의한 전달은 같은 메모리 주소의 같은 객체 값을 공유하고 있는 것이다.




다시 돌아와서 참조에 의한 전달을 했을 때는 다음과 같은 현상이 일어난다.
let lt = res = []
lt.push(1)

console.log(lt) // [1]
console.log(res) // [1]

res.push(2)

console.log(lt) // [1, 2]
console.log(res) // [1, 2]

무심코 코드를 한 줄 줄이려 했던 욕심이 자바스크립트를 더 깊게 공부하게 된 계기가 되었고 단순히 코드를 더 잘 작성하는 것을 넘어서 배움의 즐거움을 줬던 경험이었다.

profile
프론트엔드 개발자

0개의 댓글