개발 기술/개발 이야기

클로저는 무엇일까? (feat. 외부, 내부 함수, 랙시컬 스코프)

by GicoMomg 2021. 11. 29.

이 포스팅에서는 내부, 외부함수를 알아보고 클로저, 클로저와 연관된 랙시컬 스코프에 대한 간단히 알아본다.

1. 클로저와 내부, 외부 함수

  • 클로저중첩 함수에서 외부 함수가 종료되어도 내부 함수에서 외부 함수에 접근할 수 있는 환경을 말한다.
  • 내부 함수는 함수 안에 선언된 함수를 뜻하며, 외부 함수는 내부 함수를 포함하고 있는 함수를 말한다.
  • 아래 예시에서 outer()는 외부함수, inner()는 내부함수이다.
function outer(){             // 내부 함수를 포함하고 있는 외부 함수
  const inner = function() {  // 특정 함수 내부에 선언된 내부 함수
    console.log('hello')
  } 
  inner();   
}
outer();  // hello
  • outer()는 중첩 함수 형태이며, inner()(내부함수)는 outer()(외부함수)에서 선언되어 있다.

그런데, 내부함수를 생성하는 이유는 무엇일까?

  • 그 이유는 특정 함수에서 사용할 함수를 정의할 때, 내부함수로 선언하면 응집성 측면에서 좋기 때문이다.
  • 아래 예시를 보면, inner()outer()바깥에서는 호출될 수 없다. (prviate로 사용 가능)
  • 그렇기 때문에 inner()의 사용 범위를 제한할 수 있다. (응집성 보장)
function outer(){    
  const inner = function() {
    console.log('hello')
  } 
  inner();   
}
inner();  // inner is not defined



2. 클로저는 무엇일까

  • 앞서 언급했듯이 클로저외부 함수가 종료되도 내부 함수에서 외부 함수에 접근할 수 있는 환경을 말한다.

내부함수가 외부함수에 접근할 수 있다? 이 말은 무엇을 뜻하는 걸까?

  • 이 말은 내부 함수가 외부 함수의 지역 변수에 접근할 수 있음을 뜻한다.
  • 예시를 살펴보자!

(1) 클로저 예시 1

  • 이번에도 outer(), inner()함수를 가져와보았다.
  • 외부함수인 outer()에서는 title 변수와 inner()가 선언되어 있다.
function outer(){
    var title = 'coding everybody';    // 외부 함수에 정의된 지역 변수
    function inner(){}                 // 외부 함수에 선언된 내부 함수
    inner();
}

  • 클로저가 가능하다면, inner()에서 outer()의 지역변수에 접근할 수 있을 것이다.
function outer(){
  var title = 'coding everybody';    //외부함수에 정의된 지역변수
  function inner(){        
    console.log(title);              // 내부함수에서는 외부함수의 지역변수에 접근할 수 있음
  }
  inner();
}

  • outer()를 호출해보면, inner()console.log(title)이 실행되고,
  • inner()title이 없기 때문에, inner()의 외부함수(outer())의 title을 사용하게 된다.
outer();  // coding everybody

(2) 클로저 예시 2

  • 그렇다면, 외부 함수에서 내부 함수를 return하는 경우에는 어떻게 될까?
  • outer()에서는 arrow function을 리턴하고 있다.
  • 리턴을 하면 해당 함수의 로직은 종료되며, 내부에 선언된 변수가 소멸되는 게 자연스럽다.
function outer(){                    
  var title = 'coding everybody';    
  return () => (console.log(title))   // arrow function
}

  • 하지만 실제로 outer()를 실행해보면 title 변수가 출력된다.
const inner = outer();    
inner();                   // coding everybody

리턴을 하면 해당 함수가 종료되고 함수 내부에 선언된 값들이 소멸될텐데 왜 값에 접근할 수 있을까?

  • 그 이유는 내부 함수에서 외부 함수의 지역 변수를 사용하는 경우, 외부 함수의 변수를 소멸시키지 않기 때문이다.



3. 왜 접근할 수 있을까?

  • 우리는 예시를 통해, 내부함수에서 외부함수의 지역변수에 접근(클로저)할 수 있음을 알게 되었다.

그런데 외부 함수의 지역변수에 접근할 수 있는 이유가 무엇일까? 왜 클로저가 가능한걸까?

  • js에서는 스코프라는 말이 존재한다.
  • 스코프란, 변수에 접근가능한 범위를 얘기한다.
  • 크게 지역 스코프, 전역 스코프가 있는데, 클로저에는 그 중 랙시컬 스코프 개념이 중요하다.

랙시컬 스코프는 무엇인가요?

  • 랙시컬 스코프는 함수를 어디(where)에 선언하느냐에 따라 함수 접근 범위가 결정되는 걸 말한다.
  • 함수는 이 랙시컬 스코프로 인해 자신의 상위 함수에 접근할 수 있다.
  • 만약 A() 내부에 B()선언했다면, 랙시컬 스코프에 의해 B()는 (B()의 상위인)A()에 접근할 수 있다.
function A() {
  const a = 12;
  function B() {
    console.log(a);  // A()의 a변수에 접근 가능
  }
}
  • 결국 랙시컬 스코프로 인해, 클로저가 가능해지는 것이다.

추가적으로 랙시컬 스코프에 대한 알고 싶다면 이 링크를 확인해보자 🙂



반응형

댓글