어서와, 개발은 처음이지?

자바스크립트 변수, 파라미터와 메모리 참조 본문

Javascript

자바스크립트 변수, 파라미터와 메모리 참조

오지고지리고알파고포켓몬고 2018. 9. 21. 20:00
반응형


메모리는 변수나 값이 저장되는 공간입니다.


메모리에 대한 이야기가 낯설다면, 내 코드가 실행될 때 내가 선언한 변수, 함수, 실행문들이 어딘가에 담겨지고, 그곳이 메모리구나 정도로 생각하시면 되겠습니다.


클로저(Closure)에 대한 이해를 돕기위해, 메모리 측면에서 변수나 함수의 파라미터가 함수 안에서 어떻게 동작하는지 알아보는 시간을 갖겠습니다.



  mutable 객체와 immutable 객체  


자바스크립트 자료형 중 String(문자열), Number(숫자), Boolean(참/거짓), undefined, null은 immutable(변경불가능한) 객체 입니다.

반대로 Function(함수), Array(배열), Object(객체)은 mutable(변경가능한) 객체 입니다.(immutable하지 않은 모든 것들)

<메모리 영역의 어딘가>

자바스크립트에서 변수를 선언하고 값을 할당하면, 값이 메모리의 어딘가에 위치하게 되는데 이곳을 편의상 immutable 영역과 mutable 영역이라고 구분하여 부르겠습니다.



  mutable 객체의 메모리 참조  


변경 가능하다? 변경 불가능하다? 잘 와닿지 않지만 일단 아래 코드를 보겠습니다.

var obj1 = {};
var obj2 = obj1;

obj1.value = 100;

console.log(obj1); // { value: 100 }
console.log(obj2); // { value: 100 }

객체의 참조에 대해 이야기 할때 흔하게 나오는 예 입니다.

이 코드는 메모리 영역을 들여다보면 아래와 같은 모양을 하고있습니다.

<mutable 객체가 참조되는 모습>

obj1의 값을 변경해도 obj2에 반영되는 이유는 위 그림처럼 obj1와 obj2가 실제로는 mutable 영역의 같은 객체를 참조도록 작성되었기 때문입니다.(var obj2 = obj1)

var obj1 = {};
var obj2 = {};

obj1.value = 100;

cconsole.log(obj1); // { value: 100 }
console.log(obj2); // { }

하지만 위처럼 새 객체를 할당하는 것으로 별도로 관리할 수 있습니다.

<같은 빈 객체이지만 다른 영역에 생성된 모습>



  immutable 객체의 메모리 참조  


immutable 객체로 위와 같은 예를 실행해보겠습니다.

var num1 = 0;
var num2 = num1;

num1 = 100;

console.log(num1); // 100
console.log(num2); // 0

코드를 실행하면 mutable 객체를 수정힐 때와 다른 결과를 보입니다.

이 코드는 메모리 영역을 들여다보면 아래와 같은 모양을 하고있습니다.

 

<immutable 객체가 참조되는 모습>

num1 = 100에서 immutable영역의 0이 변경되지 않고 100이라는 값이 새로 할당됩니다.

mutable 객체의 값이 변경(obj1.value = 100)되는 모습과 다르게 동작하는 것을 볼 수 있습니다.


눈치 채셨겠지만 mutable한 객체, immutable한 객체는 메모리가 참조중인 값이 직접 '변경'되는지, 새로운 참조값이 할당되는지를 기준으로 구분된 것 입니다.


잘 이해가 안되신다면 메모리 영역의 값이 직접 변경된다 vs 새로 할당된다 정도의 느낌을 가지고 넘어가시면 됩니다.



  함수에서의 참조(파라미터)  


위에 언급한 내용은 모두 함수에서의 참조를 설명하기 위한 포석이였습니다.

메모리 영역의 값이 직접 변경된다 vs 새로 할당된다 정도의 느낌을 잘 기억해주세요.

var score = 80;
var person = {name:'yuddomack', age:28};
function changeScore(score){
  score = 30;
}
function changeName(person){
  person.age = 40;
}

changeScore(score);
changeName(person);
console.log(score); // 80
console.log(person); // { name: 'yuddomack', age: 40 }

위 코드는 changeScore를 통해 score를 30으로 바꾸고, changeName을 통해 person객체의 age를 바꾸도록 하고있습니다.

그런데 person객체의 age는 변경되었지만 score는 여전히 80을 나타내고있습니다.


변수는 유효 스코프에서 생성되고 소멸됩니다. 자바스크립트의 var 변수는 함수내에서 유효합니다.

낯설게 들리신다면 호이스팅에 대해 언급한 글을 읽어봐주세요.


때문에 글로벌 영역 뿐만 아니라 함수가 실행되는 동안 메모리 상에 함수의 파라미터(혹은 지역 변수)를 위한 공간도 생겨납니다.


초기에는 score에 immutable한 값, person에 mutable한 값이 할당됩니다.

(엄밀히 따지면 name과 age는 immutable영역의 값을 참조합니다.)



각 함수가 실행되면 메모리에서는 위와 같은 변화가 일어납니다.

changeScore()에서 지역 변수 score는 40이라는 값을 새로 참조하고, 함수(유효 스코프)가 종료되며 소멸하게됩니다.


글로벌 변수 score는 여전히 80을 참조하고 있습니다.


changeName()에서 지역 변수 person가 참조하고 있는 mutable 객체는 값이 변경되고, 같은 객체를 참조하는 글로벌 변수 person역시 영향을 받게 됩니다.

var score = 80;
function changeScore(score){
  var score = score;
  score = 30;
}

함수의 parameter도 사실상 위와 같이 유효범위 최상단에 지역변수로 선언되어 할당되는 꼴이라고 볼 수 있습니다.



  클로저(Closure)  


글로벌 영역의 score를 함수에서 수정할 수 있을까요?

자바스크립트의 함수는 선언된 시점의 언어적(lexical) 유효범위를 가진다고 합니다.


아래 코드를 보겠습니다.

var score = 80;
function changeScore(){
  score = 30;
}

changeScore();
console.log(score); // 30

콘솔에서 30이 출력되는 것을 볼 수 있습니다.

chnageScore의 score가 함수 외부의 score를 가리키고 있기 때문입니다.



함수가 언어적(lexical) 유효범위를 갖는다는 것은 쉽게 표현하면 함수 밖에서 선언된 값을 함수 안에서 사용할 수 있다는 말 입니다.

score = 30이 실행되면 글로벌 변수 score에 30이 새로 할당됩니다.


호이스팅된 코드로 생각하면 조금 더 합리적으로 느껴집니다.

var score;
function changeScore(){
  score = 30;
}

score = 80;

changeScore();
console.log(score); // 30

이렇게 함수 밖에서 선언된 값을 함수 안에서 사용하면 클로저가 생성되는데,

클로저에 관한 내용은 다음 글에서 자세히 다뤄보겠습니다.



Comments