코딩기록

JS)모던 자바스크립트 Deep Dive 14장 전역 변수의 문제점 본문

프론트/모던 자바스크립트 Deep Dive 책 스터디

JS)모던 자바스크립트 Deep Dive 14장 전역 변수의 문제점

뽀짝코딩 2024. 7. 18. 16:41
728x90

14장 전역 변수의 문제점

14-1. 변수의 생명 주기

  • 변수는 선언에 의해 생성되고 할당을 통해 값을 갖음.
  • 언젠가 소멸하는 생명주기가 있고 자신이 선언된 위치에서 생성되고 소멸함.

 

1). 지역 변수의 생명 주기

  • 함수 내부에서 선언된 지역 변수는 함수가 호출되면 생성되고 함수가 종료하면 소멸.
  •  
  • [예제 14-01] 의 지역 변수 x는 foo 함수가 호출되기 이전까지는 생성되지 않음.
    • foo 함수를 호출하지 않으면 함수 내부의 변수 선언문이 실행되지 않기 때문.
  • 함수 내부에서 선언한 변수는 함수가 호출된 직후에 함수 몸체의 코드가 한 줄씩 순차적으로 실행되기 이전에 자바스크립트 엔진에 의해 먼저 실행.
    • ①위 예제의 foo 함수를 호출하면 함수 몸체의 다른 문들이 순차적으로 실행되기 이전에 x 변수의 선언문이 자바스크립트 엔진에 의해 가장 먼저 실행되어 x 변수가 선언되고 undefined로 초기화. 
      • ②그 후, 함수 몸체를 구성하는 문들이 순차적으로 실행되기 시작하고 변수 할당문이 실행되면 x 변수에 값이 할당. 
    • ③그리고 foo() 함수가 종료하면 x 변수도 소멸되어 생명 주기가 종료.
      • 즉, 지역 변수의 생명주기는 함수의 생명 주기와 일치.
  • 지역 변수가 함수보다 오래 생존하는 경우도 있음.
  • 변수의 생명 주기는 메모리 공간이 확보된 시점부터 메모리 공간이 해체되어 가용 메모리 풀에 반환되는 시점까지.
  • 스코프도 마찬가지로 메모리가 해제되어 소멸될 때까지 유효.
  • 일반적으로 함수가 종료하면 함수가 생성한 스코프도 소멸하지만 누군가 스코프를 참조하고 있으면 스코프는 소멸(해제)하지 않고 생존.
    • 24장 클로저에서 자세히...
    •    [ 예제 14-02 ]
         var x = 'global';
         
         function foo() {
           console.log(x);  // ①
           var x = 'local';
           console.log(x);  // ② 
         }

         foo();
         console.log(x); // global
      1. 지역 변수 x는 ①의 시점에 이미 선언되었고 undefined로 초기화됨. 
        • 지역 변수 x를 참조해 값을 출력함.
        • 변수 할당문이 실행되기 전까지 undefined 값을 갖음.
          • 이처럼 호이스팅은 스코프를 단위로 동작.
      2. 지역 변수 x에 'local'이 할당되어 ②에 출력됨.

 

2). 전역 변수의 생명 주기

  • 전역 변수의 생명주기는 애플리케이션의 생명 주기와 같음.
  • 함수와 달리 전역 코드는 코드가 로드되자마자 곧바로 해석되고 실행됨.
  • 반환문을 사용할 수 없어 마지막 문이 실행되어 더 이상 실행할 문이 없을 때 종료.
  • 브라우저 환경에서 전역 객체는 window이므로 브라우저 환경에서 var 키워드로 선언한 전역 변수는 전역 객체 window의 프로퍼티.
    • 브라우저 환경에서 var 키워드로 선언한 전역 변수는 웹페이지를 닫을 때까지 유효.
    • 즉, var 키워드로 선언한 전역 변수의 생명 주기는 전역 객체의 생명 주기와 일치.
    •  

 

 

14-2. 전역 변수의 문제점

문제점 4가지

  1. 암묵적 결합
    • 전역 변수를 선언한 다는건 코드 어디서든 참조하고 할당할 수 있는 변수를 사용하겠다는 의도.
    • 이는 모든 코드가 전역 변수를 참조하고 변경할 수 있는 암묵적 결합을 허용하는 것.
      • 변수의 유효 범위가 크면 클수록 코드의 가독성은 나빠지고 의도치 않게 상태가 변경될 수 있는 위험성도 높아짐. 
  2. 긴 생명 주기
    • 전역 변수는 생명 주기가 길어 메모리 리소스도 오랜 기간 소비 함.
      • var 키워드는 변수의 중복 선언을 허용해 생명 주기가 긴 전역 변수는 변수 이름이 중복될 가능성이 있고 의도치 않은 재할당이 이뤄지게 됨.
  3. 스코프 체인 상에서 종점에 존재
    • 전역 변수는 스코프 체인 상에서 종점에 존재해 변수를 검색할 때 전역 변수가 가장 마지막에 검색됨.
      • 즉, 전역 변수의 검색 속도가 가장 느림.
  4. 네임스페이스 오염
    • 자바스크립트의 가장 큰 문제점 중 하나는 파일이 분리되어 있다 해도 하나의 전역 스코프를 공유한다는 것.
    • 따라서 다른 파일 내에서 동일한 이름으로 명명된 전역 변수나 전역 함수가 같은 스코프 내에 존재할 경우 예상치 못한 결과를 가져올 수 있음. 

 


14-3. 전역 변수의 사용을 억제하는 방법

  • 전역 변수를 반드시 사용해야 할 이유를 찾지 못한다면 지역 변수를 사용해야 함.
  • 변수의 스코프는 좁을수록 좋음.

 

1). 즉시 실행 함수

  • 함수 정의와 동시에 호출되는 즉시 실행 함수는 단 한 번만 호출됨.
  • 모든 코드를 즉시 실행 함수로 감싸면 모든 변수는 즉시 실행 함수의 지역 변수가 됨.
  • 전역 변수를 생성하지 않으므로 라이브러리 등에 자주 사용됨.

 

2). 네임스페이스 객체

  • 전역에 네임스페이스 역할을 담당할 객체를 생성하고 전역 변수처럼 사용하고 싶은 변수를 프로퍼티로 추가하는 방법.
  •    [예제 14-06]
       var MYAPP = {} // 전역 네임스페이스 객체
       
       MYAPP.person = {   // 또 달른 네임스페이스 객체를 프로퍼티로 추가해서
         name: 'Lee',     // 네임스페이스를 계층적으로 구성
         address: 'Seoul'
       };
     
       console.log(MYAPP.name);  // Lee
  • 네임스페이스를 분리해서 식별자 충돌을 방지하는 효과는 있으나 네임스페이스 객체 자체가 전역 변수에 할당되므로 유용해 보이지 않음.

 

3). 모듈 패턴

  • 클래스 모방해서 관련이 있는 변수와 함수를 모아 즉시 실행 함수로 감싸 하나의 모듈을 만듬.
  • 클로저 기반으로 동작.
  • 전역 변수의 억제는 물론 캡슐화까지 구현 가능.
    • 24장 클로저에서 자세히...
    • 캡슐화(encapsulation)
      • 캡슐화는 객체의 상태를 나타내는 프로퍼티와 프로퍼티를 참조하고 조작할 수 있는 동작인 메서드를 하나로 묶은 것.
      • 객체의 특정 프로퍼티나 메서드를 감출 목적으로 사용하기도 하는데 이를 정보 은닉(access modifier)이라함. 
  • 자바스크립트는 public, private, protected 등 접근 제한자 대신 전역 네임스페이스의 오염을 막는 기능은 물론 한정적이긴 하지만 정보 은닉을 구현하기 위해 모듈 패턴을 사용.
  •   [ 예제14-07 ]
       var Counter = (function () {
         // private 변수
         var num = 0;
       
         // 외부로 공개할 데이터나 메서드를 프로퍼티로 추가한 객체를 반환.
         return {
           increase() {
             return ++num;
            },
           decrease() 
             return --num;
            }
          };
        }());
       
       // private 변수는 외부로 노출되지 않음.
       console.log(Counter.num);   // undefined
       
       console.log(Counter.increase());    //  1
       console.log(Counter.increase ());   //  2
       console.log(Counter.decrease());   //  1
       console.log(Counter.decrease());   //  0
  • [예제 14-07]은 즉시 실행 함수는 객체를 반환. 이 객체에는 외부에 노출하고 싶은 변수나 함수를 담아 반환.
    • 이때반환되는 객체의 프로퍼티는 외부에 노출되는 퍼블릭 멤버.
  • 노출하고 싶지 않은 변수나 함수는 반환하는 객체에 추가하지 않으면 외부에서 접근할 수 없는 프라이빗 멤버.
    • 24장 클로저에서 자세히...

 

4). ES6 모듈

  • ES6 모듈 사용 시, 전역 변수 사용 불가능.
  • 파일 자체의 독자적인 모듈 스코프 제공.
  • 모듈 내에서 var 키워드로 선언한 변수는 더는 전역 변수나 window 객체의 프로퍼티가 아님. 
  • 모던 브라우저에서 ES6 사용 가능.
    • Chrome 61, FF 60, SF 10.1, Edge 16 이상.
      • ES6 모듈 사용 방법
        • <script> 태그에 type="module" 어트리뷰트 추가.
        •   <script type="module" src="./main.js"></script>
        • 로드된 자바스크립트 파일은 모듈로서 동작.
        • 모듈의 파일 확장자는 mjs 권장. 
  • IE를 포함한 구형 브라우저에서 동작하지 않음.
  • 브라우저의 ES6 모듈 기능을 사용하더라도 트랜스파일링이나 번들링이 필요해 아직까지는 브라우저가 지원하는 ES6 모듈 기능보다는 Webpack 등의 모듈 번들러를 사용하는 것이 일반적임.
    • 모듈과 Webpack 등의 모듈 번들러를 도입하는 방법은 48장 모듈과 49장 Babel과 Webpack을 이용한 ES6+/ES.NEXT 개발 환경 구축에서 자세히...

 

 

덧, 프로젝트 진행시 모듈을 안쓸 수가 없다. 그래서 모듈 쓰면 전역 변수가 해결됨.

 

 

 

 

 

 

참고

도서 - 모던 자바스크립트 Deep Dive -이웅모

이웅모 강사님 홈피  -  https://poiemaweb.com/js-prototype

이웅모 강사님 유튜브  -  https://www.youtube.com/watch?v=0AjTZG6bGq8


✅ 덧, 부분은 스터디 내용을 기억에 의존해서 쓴 글이라 틀린 부분이 있다면 댓글 부탁드립니다.- 뽀짝코딩 주인장-

 

 

 

반응형
Comments