ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JavaScript] 스코프 (Scope)와 클로저 (Closure)
    👩🏻‍💻 정리/JavaScript 2021. 8. 25. 22:42

    목차

    1. 스코프란?
    2. 스코프의 종류
        2.1 Global(전역) 스코프
        2.2 Local(지역) 스코프
    3. 스코프 체인
    4. 클로저란?
    5. 참고 링크


    1. 스코프란?

    스코프(Scope)는 '유효 범위'라는 뜻으로, 변수가 유효한(살아 있는) 범위라고 할 수 있다.

    var x = 'global';
    
    function foo () {
      var x = 'function scope';
      console.log(x); // function scope
    }
    
    foo();
    console.log(x); // global

    스코프가 존재하기 때문에 우리가 변수를 중복해서 사용할 수 있는 것이다. 만약 스코프가 없었다면 코드 전체에 절대 충돌하지 않는 변수(식별자)명을 딱 하나만 써야 한다!

    2. 스코프의 종류

    2.1 Global(전역) 스코프

    코드 어디에서든지 참조가 가능하다. var로 선언한 변수는 전역 객체에 속하게 된다.(= 프로퍼티가 된다)

    var a = "hello"
    
    console.log(a); // hello
    console.log(window.a); // hello
    ✅ Client(브라우저)의 전역 객체는 window
    ✅ Node.js에서의 전역 객체는 global

    2.2 Local(지역) 스코프

    자바스크립트에서의 스코프는 다른 언어와 달리 함수 블록 내이다. ({} 블록과 상관 없음!)
    즉, 함수에 의해서만 스코프가 생성된다.

    if (true) {
      var x = 5;
    }
    
    console.log(x);  // 5

    ▲ if 문 안에 있더라도, 함수 블록이 아닌 일반 블록이므로 x는 전역 변수가 된다! 외부에서도 접근 가능!

    (function () {
      var x = 5;
    })();
    
    console.log(x);  // Uncaught ReferenceError: x is not defined

    ▲ 오로지 함수만 Local 스코프를 생성한다! 

    ❗ 단, let, const로 변수를 선언할 때의 스코프는 블록({}) 단위이다.

    { 
      let x = 1; 
    }
    
    console.log(x); // Uncaught ReferenceError: x is not defined

    3. 스코프 체인

    변수가 해당 스코프에서 유효하지 않을 때, 안에서부터 바깥으로 차례대로 검색해 나가는 것을 말한다. 아래 코드를 살펴보자!

    function sum() {
    
      var a = 3; 2️⃣
      var b = 5; 
    
      function inner() {
      
    	var b = 7; 5️⃣ 
    	var c = 11; 
    
    	a = a + b + c; 6️⃣ // a = 3, b = 7, c = 11 
    	console.log(a); 7️⃣ // 21 
    
      };
    
      console.log(a); 3️⃣ // 3 
      inner(); 4️⃣  
      console.log(a); 8️⃣ // 21
    };
    
    sum(); 1️⃣
    console.log(a); 9️⃣ // Uncaught ReferenceError: a is not defined

    1️⃣ sum 함수 호출.
    2️⃣ var a, b가 선언되고 3, 5라는 값이 할당됨.
    3️⃣ a를 console로 찍으면 2️⃣에 할당된 3을 출력함.
    4️⃣ inner 함수 호출.
    5️⃣ var b, c가 선언되고 7, 11이라는 값이 할당됨.
    6️⃣ a에 a, b, c의 합을 할당하는데, 이때 a는 inner 함수 내에 존재하지 않아 밖으로 나가 sum 함수에서 찾아옴. ← 이게 바로 스코프 체인!
    7️⃣ 그렇게 3,7,11의 합 21이 a에 재할당됨.
    8️⃣ a를 console로 다시 찍어보면 7️⃣에 재할당된 21을 출력함.
    9️⃣ 아예 sum 함수까지 종료되고 나와서 전역에서 a를 console로 찍어보면 a는 정의되지 않았다는 ReferenceError 발생.

    4. 클로저란?

    클로저(closure)는 내부 함수가 외부 함수의 맥락(context)에 접근할 수 있는 것을 가리킨다. 클로저는 자바스크립트를 이용한 고난도의 테크닉을 구사하는데 필수적인 개념으로 활용된다. "함수가 선언됐을 때"가 중요한데, 즉, 함수를 선언할 때 만들어진 스코프가 사라진 후에도 호출할 수 있는 함수를 말한다. 스코프가 다 끝나 더 이상 접근할 수 없는 변수임에도 그 변수를 사용할 수 있는 것이 바로 클로저이다.

    구체적으로 설명하자면, 어떤 함수 A에서 선언한 변수 a를 참조하는 내부 함수 B를 외부로 전달할 경우, A의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상이다. 예시 코드를 한번 살펴보자.

    var A = function() {
    	var a = 1;
    
    	var B = function() {
    		return ++a;
    	};
    
    	return B;
    };
    
    var outer = A();
    console.log(outer());  // 2
    console.log(outer());  // 3

    1. var outer = A()에서 함수 B 자체를 반환한다.
      a. A()는 실행됐으므로 A의 실행 컨텍스트는 종료된다.
      b. outer 변수는 이제 B 함수를 바라보고 있는 상황.

    2. outer()로 outer 함수를 호출하면, 즉, B가 호출되고 a값은 계속 증가한다.
      a. B 함수에는 a의 유효 범위가 아니므로, 한번 더 바깥의 A의 scope를 참조하고 계속 값이 증가한다.

    💡 메모리 관리
    자바스크립트는 원래 메모리 관리에 신경 쓰지 않아도 된다. 사용하지 않는 변수는 알아서 Garbage Collector에 수집되기 때문이다. (실행 컨텍스트를 참고하여 동작함)

    그런데 클로저에서는 의도적으로 변수를 사용하므로 메모리가 계속 소모된다. 만약 Garbage Collector에 수집되게 하려면 null이나 undefined를 할당하면 된다.

    💡 가비지 컬렉션(Garbage Collection)
     가비지 컬렉션은 말 그대로 '쓰레기 수집'이라는 뜻으로, 프로그램이 동적으로 할당했던 메모리 영역 중에서 필요 없게 된 영역을 해제하는 메모리 관리 기법 중 하나이다. 필요없게 된 영역이란, 어떤 변수도 가리키지 않게 된 영역을 의미한다.

    5. 참고 링크

    🔗 <코어 자바스크립트> - 정재남 저.
    🔗 클로저 생활코딩