JS 클로저 ( Closure )

조 은길·2021년 10월 14일
0

Javascript 정리

목록 보기
11/48
post-thumbnail
  • Achievement Goals
    • Closure의 정의와 특징에 대해서 이해할 수 있다.
    • Closure를 활용해서 외부함수의 변수에 접근할 수 있다.
    • Closure의 유용하게 쓰이는 몇 가지 코딩 패턴을 이해할 수 있다

들어가기 앞서,

본격적으로 클로저에 대해서 들어가기 전에, 필요한 개념 점검부터 해보자!

  • 정답 : innerFn이 접근할 수있는 스코프는 "innerFn, outerFn 그리고 전역" 총 3개가 존재한다.

이제, 이걸 바탕으로 다음 문제를 풀어보자.

  • 정답 : 1. 'outer' 'inner' 2. 실행되지 않은 innerFn 3. 'inner'


JS의 특징 중 하나는 함수 자체를 return하는 것이 가능하다는 것이다. 그리고 바로 이것이 가능하기 때문에, "클로저"라는 개념을 사용할 수 있다.


클로저란??

폐쇄된 공간에 대한 접근 권한을 가진 함수를 말한다. 한 마디로 말하자면, 외부함수에 접근할 수 있는 내부함수이다.

한 눈에 봤을 때, 전혀 새로운 개념은 아니다. 그냥 스코프 법칙 중에 하나인데, 여기에 클로저라는 이름을 붙여놓은 거라고 한다.

그런데, 무언가에 용어를 붙여주는데는 이유가 있지 않을까??
바로, 이런 패턴이 자주 쓰이고, 유용하기 때문이다.


클로저의 유용성

- 1. 커링

정리해보자면, 외부함수에 변수를 내부함수가 계속 쓰면서, 뭔가 재사용할 수 있는 탬플릿 함수같이 쓸 수 있는 게 특징이다.

위의 예시를 보면, add100에 x값을 고정해놓고, y값만 계속 바꿔서 쓰는 것을 볼 수 있다. 이를 통해서, 함수의 재사용이 가능해진다.

커링의 또다른 예시를 하나 보자!!

HTML을 만들 때, 이런식으로 x값에 원하는 tag값만 설정해놓고, y값으로 태그에 짚어넣고 싶은 단어만 짚어넣는다면, 매우 쉽게 태그 찍어내는 기계를 만들어낼수 있는 동시에, 함수를 여러개 선언 하지 않아도 된다. 즉, 하나의 함수로 많은 일들을 할 수 있는 재사용성이 높아진다.

그런데, 한가지 궁금한 점이 있다.

Q. 만약 내부 함수가 외부 함수보다 오래 살아 있는 경우에, 외부함수에 있던 변수들은 어떻게 될까??

let outer = function(){
 let a= 1; // 외부 함수에 존재하는 변수
 
    let inner = function(){
      let b = 5;
      let c = 6;
	  console.log( "더하기 전 a값은 ", a); // => 1
      a = a + b + c; 

      console.log(a); // => 12 상위 부모 변수에 접근할 수 있다.
    }
  return inner;
}
const innerFromOuter = outer(); // => 실행되지 않은 inner함수 반환
innerFromOuter(); //  => 12 

뭔가 이상하다.

변수 a는 outer 함수에만 존재하기 때문에, return inner;가 된 순간, 파괴되어야 할 텐데, inner 함수 안에서 a를 소환할 수가 있다.

다시 말해서, inner는 outer가 이미 return된 후에도, outer의 변수 a에 대한 접근권한을 가진다.
그 이유는 함수는 자신을 포함한 함수의 스코프에 접근할 수 있기 때문이다. 그렇게 때문에, a변수는 메모리에서 해제가 되지 않고 있다.

=> 이 부분이 이해가 안 된다면, 맨 처음에 내준 문제를 다시 한 번 보자!

그래서 클로저는 이렇게 오직 내부함수만 접근할 수 있는 폐쇄된 공간에 접근 가능한 함수를 말한다.

- 2. 클로저 모듈 패턴

예시에서 privateCounter는 누구도 직접적으로 바꿀 수없다. 그러나, 내부함수들로 간접적으로 바꾸는 것은 가능하다.

- 장점 1. 중요한 변수의 직접적인 변경 방지

좀 더 깊은 이해를 위해, 다른 예시를 하나 더 보자!

person.age를 30으로 바꿨고, person.age를 출력했을 때는 30이 찍힌다. 그렇다면, person.getAge( );를 출력했을 때도 30이 나와야 할텐데, 왜 그래로 15로 나오는 걸까??

바로, person.age와 person.getAge() 대상이 달라서 그렇다.

person.age는 전역에서 접근할 수 없기 때문에, 존재하지 않는다. 구지, 이런식으로 접근해보고 싶다면, return {...} 안에 만들어야 한다. 즉, 내부 함수(=클로저)를 사용해야 한다.

다시 말해서, person.age = 30; 할 때 처음 만들어졌다. 그리고 이렇게 let이나 const 없이 만들어진 변수는 전역 객체에 연결되서 전역 변수가 된다. 그래서 맨 마지막 줄이 true가 된다.

그리고, person.getAge()는 outer의 var age를 가져온다. 내부 함수를 통해서 접근이 가능하기 때문에...

=>바로 이게 접근 불가능한 비공개 객체 만들기이다!!

- 장점 2. 각각 독립적인 privateCounter를 가지고 있어서, 객체처럼 재사용이 가능해진다.

counter1과 counter2는 각각 독립적인 privateCounter 변수를 가지고 있다. 그래서, counter1의 변화가 counter2에 영향을 주지 않는다.

즉, 여러 함수를 선언할 필요 없이 하나의 함수만으로 재활용이 가능해진다. 마치 객체같다.

  • 요점 정리

    • 자바스크립트는 내부 함수에서 자신을 포함하는 외부 함수의 스코프에 접근할 수 있다.
    • 내부 함수가 살아 있는 상태에서 외부 함수가 파괴되면, 외부 함수의 변수들에 대한 접근 권한은 내부 함수만 가지게 된다.
    • 이렇게 폐쇄된 공간에 대한 접근 권한을 가진 함수가 클로저 이다.

클로저의 단점

클로저의 단점으로는 잘못 사용했을 시, 성능 문제와 메모리 문제가 발생할 수 있다.

  • closure의 비공개 변수는 자바스크립트에서 언제 메모리 정리 해야할 지 모르기 때문에 자칫 메모리 낭비로 이어질 수 있다. 프로그램을 만들면서 메모리 문제가 발생한다면, 클로저를 의심해보자.
  • scope chain을 거슬러 올라가는 행동을 하기 때문에 조금 느리다.

- IIFE ( 중요 )

위의 예제 코드 중에, ( function() { ... } )(); 구문의 함수가 있었다.

이 함수를 IIFE(= 즉시 호출 함수 표현식)이라고 부른다. 모듈 패턴이라고도 하는데, 함수를 선언하자마자 바로 실행시켜버리는 게 특징이다. 함수를 function() {}로 선언하면서, 동시에 ()를 붙이니까 즉시 실행되는 원리이다. 비공개 변수가 없는 자바스크립트에 비공개 변수 기능을 만들어주기 때문에, 이 구문을 많은 라이브러리가 활용하고 있다고 한다. ( 라이브러리는 개발자만 접근할 수 있는 private 영역과 public 영역으로 구분할 필요가 있다. private 영역이 없으면, 누구든지 함부로 라이브러리를 바꿀 수 있기 때문에 꼭 필요하다. ) 이 패턴은 꼭 기억하고 있자!


클로저는 필요한가??


자료 출처 및 참고 자료

오늘 TIL은 코드스테이츠에서 학습한 내용과 개인적으로 보충 학습한 내용들을 바탕으로 작성됐다.

알고 보면, 크게 어려운 내용도 아닌데, 왜 설명을 굉장히 어렵게 써놓으셨는지들...
그저 웃지요~~~

실행 컨텍스트와 클로저

자바스크립트 클로저, 쉽게 이해하기

익명 함수와 클로저는 보통 함께 다닐 때가 많습니다

profile
좋은 길로만 가는 "조은길"입니다😁

0개의 댓글