티스토리 뷰

global execute context 에서 실행될 때 

a=1 Global
var a = 1 Global
let a =1  Script
const a =1 Script

 

function execute context 에서 실행될 때

a=1 Global
var a = 1 Local
let a =1  Local
const a =1 Local

*let 과 const 는 함수 안에서가 아니라 block 안에서 local로 들어간다. 

 

Closure(클로져) 

  • self-invocation을 한 함수의 리턴값을 변수에 할당한다. 
  • 리턴을 익명함수로 선언하면 변수는 그 익명함수를 리턴받게 된다.
  • 변수명에 함수를 실행하는 ()연산을 하면 리턴으로 받은 함수만 실행되고, self-invocation이 되었던 함수는 메모리에 상주한 상태로 대기하게 된다. 
  • 부모 함수의 실행상태를 대기시키고 닫는다(폐쇄)는 의미로 클로져라고 부른다.

ex) 

let getMyNum = (function (){

const myNum = 10; // 외부에서 접근 및 변경 절대 불가

return function(num){

return myNum * (Math.floor(Math.random()*num)+1)

};

})(); //내부에서 익명함수 실행

console.log(getMyNum(100));

 

 

디버거로 클로저 이해하기

TIP: 참고로 개발자 도구에서 디버거를 사용하려면 브레이크 포인트를 걸고 f5(새로고침)을 해줘야 합니다. 

  • function 이라고 체크한 버튼은 누를 시 해당 스텝에서 function 내부로 들어가 작동을 확인할 수 있습니다. 
  • Next 라고 표시한 버튼은 말 그대로 다음 function 스텝으로 넘어가는 것입니다.(함수 호출 시)
  • 어디에서 호출했느냐에 따라서 유효범위가 달라진다면 그것을 dynamic scope(동적 스코프)라고 부릅니다. 하지만 JS는 동적 스코프가 아닌 정적 스코프를 채택하고 있습니다.
    <script>
          let l0 = "l0"; //전역변수 선언
    
          function fn1() {
            let l1 = "l1";
            console.log(l0, l1); // script l0, 지역 l1
            fn2();
          }
          function fn2() {
            let l2 = "l2";
            //l1이 정의되어 있지 않다고 뜬다 -> l1 에 접근할 수 없다.
            console.log(l0, l1, l2);
          }
          fn1();
        </script>​
     
  • 그렇기 때문에 fn2()를 호출한 곳에 l1이 지역변수로 선언되어 있더라도 scope chain이 없기때문에 fn2() 내부에서 l1에 접근할 수 없게 됩니다. 그렇다면 fn1함수 내부에 fn2를 옮기면 어떻게 될까요?
    <script>
          let l0 = "l0"; //전역변수 선언
    
          function fn1() {
            function fn2() {
              let l2 = "l2";
              console.log(l0, l1, l2); // script: l0, Closure(fn1) l1 , local l2
            }
            let l1 = "l1";
            console.log(l0, l1);
            fn2();
          }
    
          fn1();
        </script>​

  • 클로저 라는 것이 local 과 Global 사이에 생겼습니다. 그리고 소괄호의 안에는 함수의 이름이 적혀있습니다. fn1 
  • 클로저를 눌러보면 l1 : "l1" 해당 함수의 로컬이 저장되어 있습니다. 여기서 클로저란 호출된 함수의 부모함수의 스코프 혹은 변수들을 동봉해서 가지고 있기 때문에 언제든지 접근할 수 있다는 의미 입니다. 이렇게 되면 함수는 오류없이 정상적으로 작동하게 됩니다. script: l0, Closure(fn1) l1 , local l2
  • 이처럼 어떤 호출된 함수의 유효범위는 어디서 실행되느냐(동적 스코프 채택)의 문제가 아니라 어디서 정의(정적 스코프 채택)되었느냐에 따라서 달라집니다. 
  • JS는 static scope or lexical scope(정적 스코프)를 채택하고 있습니다.

결론: 부모 함수 안에서 자식 함수를 선언하면 자식함수를 어디에서 호출하더라도 자식함수 안에서 부모함수의 변수에 접근할 수 있다(클로저). 

 

활용예시

 <script>
      function 더하기함수공장(초기값) {
        function 덧셈(숫자) {
          return 초기값 + 숫자;
        }
        return 덧셈;
      }

      let 더하기1 = 더하기함수공장(1);
      console.log(더하기1(1)); //output: 2
      console.log(더하기1(2)); //output: 3

      let 더하기2 = 더하기함수공장(2);
      console.log(더하기2(1)); //output: 3
      console.log(더하기2(2)); //output: 4
    </script>

all ref: https://www.youtube.com/watch?v=bwwaSwf7vkE

댓글