모듈 시스템에서 변수 바인딩 방식

개요

jeju-defense 프로젝트를 진행하던 중...

 

// 서버 관리 (점수, 골드)
export let userGold = 0; // 유저 골드
export let score = 0; // 게임 점수

 

클라이언트에서 관리하던 gold 와 score 를 서버에서 관리하도록 로직을 변경하고자, 해당 변수를 외부 모듈로 export했다.

당연히 변수를 let으로 선언하고 export 했으므로 외부 모듈에서도 값을 변경할 수 있을 줄 알았다.

 

그런데 에러가 발생하는 것이다!?

 

전개

let 으로 선언한 변수는 재할당이 가능한 거 아니었나...?

 

처음에는 이 오류를 이해하지 못했다. 나는 분명 const 가 아닌 let 으로 선언했고, 할당한 데이터의 타입과 값 또한 오류가 발생하지 않음을 확인했기 때문에 도대체 왜 이런 에러가 발생했는지 찾기가 무척 힘들었다.

 

하지만! 오랜 시간에 걸친 구글링 덕분에 원인을 발견했다!!!

 

ES6 모듈 시스템에서의 변수 바인딩 방식

  • 모듈의 독립성

ES6 모듈은 각 모듈이 독립적인 스코프를 가지므로, 모듈 내에서 let 또는 const 로 선언된 변수는 해당 모듈 외부에서 직접 변경할 수 없다. 즉, game.js에서 선언된 userGold와 score 를 import하더라도, Session.js 내에서 userGold와 score 값을 변경할 수는 없는 것이다.

 

  • 바인딩
import { userGold, score } from './game.js';

 

위 import를 통해 Session.js 는 game.js에서 정의된 userGold와 score에 대한 바인딩을 가져온다.

해당 바인딩은 userGold와 score가 어떤 값으로 설정되었는지를 기억하지만, Session.js에서 userGold 혹은 score의 값을 변경하려고 하면 에러가 발생한다. 이는 userGold와 score가 모듈의 스코프 내에서만 변할 수 있기 때문이다.

 

  • 상수처럼 동작

따라서 Session.js에서 userGold와 score는 import된 후 읽기 전용으로 취급되며, 사실상 상수처럼 동작한다. 만약 userGold와 score의 값을 변경하고 싶다면, game.js에서 직접 값을 수정해야 한다.

 

결말

결과적으로 Session.js에서 사용하는 userGold와 score는 game.js의 상태를 참조하는 것이기 때문에, 마치 const처럼 동작하여 외부에서 변경할 수 없는 특성을 가지게 된다. 이는 ES6 모듈의 설계 원리로, 모듈 간의 독립성을 유지하고 코드의 예측 가능성을 높이는 데 기여한다.

 

그럼 어떻게 해야할까?

 

뭐... 결말은 꽤나 허무했다.

나는 usergold와 score를 직접 export하는 게 아닌, get과 set을 이용하여 관리하기로 했다.

 

// 서버 관리 (점수, 골드)
let userGold = 0; // 유저 골드
let score = 0; // 게임 점수

export const setUserGold = (gold) => {
  userGold = gold;
};
export const setScore = (newScore) => {
  score = newScore;
};

export const getUserGold = () => userGold;
export const getScore = () => score;

 

이후 Session.js에 userGold와 score를 직접 사용하는 대신, setUserGold와 setScore를 import하면 에러 해결 성공!!!

 

'Side Projects' 카테고리의 다른 글

Protocol Buffers?  (4) 2024.10.24
Text-RPG(CLI) - 트러블슈팅  (1) 2024.10.22
Chrome dino 모작 - 트러블 슈팅  (1) 2024.10.07
Prisma 다시 돌아보기  (2) 2024.09.25
Session Storage / Local Storage  (0) 2024.09.23