자바스크립트 closure(클로저)란?

이정민 Lee Jeong Min·2021년 2월 21일
0

Javascript

목록 보기
5/10

어휘적 환경의 조합

중첩함수에서 내부함수가 외부함수의 환경을 기억하는것을 클로저라고 한다.
함수가 속한 문맥적 범위를 기억하여 함수가 그 범위 밖에서 실행될 때에도 접근할 수 있게 해주는 기능이라 볼 수 있다.

자바스크립트의 스코프 정의에 따라, 함수 안에서 선언된 변수는 함수 밖에서 접근할 수 없다. 하지만 함수 안에 선언된 또 다른 함수에서 접근하는 것은 가능하다.

즉, 내부의 자식 함수에서는 부모 함수의 스코프 내의 변수에 접근할 수 있는데, 부모 함수가 이미 호출이 완료되어 리턴되었을 때도 접근이 가능하다는 것이다.
이미 실행 컨텍스트 큐에서 부모 함수의 정보가 모두 사라졌음에도, 자식 함수가 아직 남아 있다면, 그 자식 함수에서는 이미 실행이 종료된 부모 함수의 컨텍스트 정보를 참조할 수 있다는 것이다.

예시1

function func() {
    var foo = 'data';
    return function() {
        return foo;
    }
}

var closure = func();
console.log(closure()); // data

func의 지역변수로 있는 foo는 func함수가 끝나면서 소멸되어야하지만, 'data'가 출력되는 것을 볼 수 있다. 이러한 현상을 클로저라 한다.

예시2

function count() {
    var num = 0;
    return function() {
        num++;
        return num;
    }
}

var closure = count();
console.log(closure()); // 1
console.log(closure()); // 2
console.log(closure()); // 3

count함수의 지역변수인 num값이 소멸되지 않고 계속 플러스되는 것을 볼 수 있다.

useState

실제로, 함수형 컴포넌트에서 상태관리를 하기 위해서는 함수가 다시 호출되었을 때 이전의 상태를 기억하고 있어야 하는데, 리액트 훅의 useState는 클로저를 통해 이를 해결한다.

const useState = (initialVal) => {
	let innerState = initialVal;
  const state = () => innerState;
  const setState = (newVal) => {
    innerState = newVal;
  }
  return [state, setState];
}

useState 함수를 실행하면, 넘어온 initialVal을 내부 상태에 할당하고, state를 호출하면 이 내부 state를 리턴하고, setState를 호출하면 새로운 파라미터로 넘어온 newVal을 내부 상태에 할당한다.

실제로 statesetState를 사용하는 시점은 useState의 호출이 끝난 후이지만, 클로저가 innerState 값을 기억하고 있기 때문에 그 이후에도 접근할 수 있는 것이다.

은닉화

클로저를 이용해서 객체지향 프로그래밍의 프라이빗 메소드를 흉내 낼 수 있는데, 이를 모듈패턴이라 한다.
모듈패턴에 대해서는 다음 글에서 더욱 자세히 다루도록 하겠다.

각 클로저는 변수에 대해 각각 다른 버전을 참조하게 되므로 서로의 변수에 영향을 주지 않는다.
이런 방식으로 클로저를 사용하여 객체지향 프로그래밍의 정보 은닉과 캡슐화 같은 이점들을 얻을 수 있다.

자바스크립트에서는 인스턴스를 생성할때 Private 변수에 대한 접근 권한 문제가 있다.

function CreateKey(key) {
    this._key = key;
}

var obj = new CreateKey('mykey');
console.log(obj._key); // myKey

obj._key = 'yourKey';
console.log(obj._key); // yourKey

변수명 앞에 _를 포함하였기 때문에 Private 변수로 쓰고 싶다는 의도를 알 수 있지만,
의도와는 달리 _key 속성은 동적으로 변경될 수 있다.

클로저를 사용한다면 외부에서 내부변수에 접근하는 것을 제한할 수 있다.

function ClosureKey(key) {
    var _key = key;
    return function() {
        console.log(_key);
    }
}

var closureObj = ClosureKey('newKey');
closureObj(); // newKey
console.log(closureObj._key); // undefined

이렇게 클로저를 활용하여 은닉화를 구현할 수 있다.

profile
https://jeong-min.com/ <- 블로그 이전했습니다 :)

0개의 댓글