[TIR] 클로저(Closure)

Jenna·2021년 1월 22일
0

TIR

목록 보기
4/4
post-thumbnail

클로저란?

오늘은 클로저 함수에 대해 복습해보도록하겠습니다.

클로저는 함수와 함수가 선언된 어휘적 환경(Lexical scoping)의 조합이다.

우리는 보통 클로저함수는 함수 내에서 함수를 정의하고 사용하면 클로저라고 합니다. 하지만 대개는 정의한 함수를 리턴하고 사용은 바깥에서 하게됩니다. 클로저는 독립적인 (자유) 변수를 가리키는 함수 또는 클로저 안에 정의된 함수는 만들어진 환경을 기억합니다.

function outer() {
    let hi = 'Hello';
    return () => { console.log(hi); };
  }
  
let greeting = outer();
greeting(); //Hello

보시다시피 outer함수 보다 그 안에 반환해주는 화살표 함수가 더 오래 유지되거나 outer 함수 밖에서 그 안의 함수가 호출되더라도 outer함수의 지역 변수에 접근할 수 있는 함수는 클로저라고 합니다.
좀 더 쉽게 설명하자면 내부의 함수가 유효한 상태에서 outer함수가 종료되어 실행 컨텍스트가 반환되어도 내부 함수에 의해 참조되고 있는 변수, 함수 선언 정보들을 스코프 체인을 통해 가지고 있습니다.
그래서 우리는 클로저를 함수와 함수가 선언된 어휘적 환경의 조합이라고 표현합니다.
또한 outer함수의 변수 hi를 자유변수라고 합니다.

function greeting(hi) {
    let name = 'Olaf';

    return (likes) => {
        return `${hi}! I am ${name}. I like ${likes}.`
    }
}

const hey = greeting('Hey');
const hello = greeting('Hello');

console.log(hey('warm hugs')); //Hey! I am Olaf. I like warm hugs.
console.log(hello('singing')); //Hello! I am Olaf. I like singing.

greeting에서는 단일인자 hi를 받아 likes가 매개변수로 있는 새 함수를 반환하여 greeting(hi)를 정의했습니다.
쉽게 말하면 greeting함수는 리턴해주는 함수를 만들어주는 아이입니다. 여기서 heyhello 는 클로저입니다. 다시한번 우리는 클로저가 리턴된 후에도 외부함수의 변수들에 접근이 가능하며 클로저에 전달되는 형태가 값 형태가 아니라는 것을 알게되었습니다.

클로저의 활용

프라이빗 메소드(private method) 흉내내기 [모듈패턴]

const light = (() => {
    let isOn = false;

    const clickSwitch = () => {
        isOn = !isOn;
    }

    return {
        click: () => {
            clickSwitch();
        },
        now: () => {
            return console.log('Is the light on now?', isOn ? 'Yes:)' : 'Nope:(');
        }
    }
}) ();

console.log(light.now()); //Is the light on now? Nope:(
light.click(); //켰다
light.click(); //껐다
console.log(light.now()); //Is the light on now? Nope:(
light.click(); //켰다
console.log(light.now()); //Is the light on now? Yes:)

이런 방식을 사용하여 객체지향 프로그래밍의 정보 은닉과 캡슐화 같은 이점들을 얻을 수 있습니다.

클로저 스코프체인

var contactNum = 119;

function contact() {
    var contactNum = 112;

    return () => { console.log(`police station's contact: ${contactNum}`);};
}

const police = contact();
police();

이 코드가 실행되는 순서입니다.
1. 화살표 함수는 경찰서의 번호를 출력하는 함수이며 contactNum의 값이 필요합니다.
2. 화살표 함수는 밖의 함수 참조를 위해 contact의 환경을 저장합니다.
3. contact를 전역에 선언된 police에 대입했습니다.
4. 전역에서 police를 호출합니다.
5. 화살표 함수는 로그를 남기기 위해 contactNum의 값을 찾습니다.
6. 화살표 함수내의 contactNum을 참조하는 값은 없습니다.
7. 밖에 있는 함수인 contactcontactNum을 찾습니다. 값은 112입니다.
8. police station's contact: 112을 출력합니다.

클로저 반복문

var i;
for (i = 0; i < 10; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
}

이 코드의 결과는 무엇일까요?
너무나도 유명하죠..? 10을 열번 출력합니다. setTimeout에 인자로 넘긴 익명함수는 1초뒤에 호출되는데 그 사이 이미 i는 10이 되어버렸기 떄문입니다.
그렇다면 어떻게 해야할까요?

var i;
for (i = 0; i < 10; i++) {
  (function(j) {
    setTimeout(function() {
      console.log(j);
    }, 100);
  })(i);
}

이렇게 한다거나 그냥 간단히 i의 범위를 바꾸기 위해 let으로 선언해줘도 됩니다.

이상 클로저와 클로저의 쓰임에 대해 복습해보았습니다.
다들 즐거운 금요일 되세여.. 앗녕~

profile
언제나 '제나'🌈 '제'일 '나'다운 기록🖊

0개의 댓글