[TIL] 클로저란? 클로저의 활용

gun·2020년 12월 21일
0

TIL

목록 보기
3/19
post-thumbnail

클로저란?

MDN에서는 클로저를 다음과 같이 정의하고 있습니다.

클로저는 독립적인 (자유) 변수를 가리키는 함수이다. 또는, 클로저 안에 정의된 함수는 만들어진 환경을 ‘기억한다’.

환경을 기억한다... 처음봤을 땐 환경을 기억한다니 무슨 소리지? 라는 생각이 먼저 들었습니다. 공부를 하다보니 내린 결론은 외부함수 안에 내부함수가 외부함수를 기억한다 라고 해석하게 되었습니다.

클로저는 어떻게 작동하는가?

function outerFunc() {
  const text = "outer" 
  return function () {
  	console.log(text);
  };
};

const closure = outerFunc()

closure()
//return outer

위에서 정의한 outerFunc를 closure변수에서 실행시켜 반환시키고, 반환된 함수는 외부함수인 outerFunc에 text변수를 참조하고 있습니다. 이렇게 참조된 변수는 outerFunc의 함수 실행이 끝났다고 해서 사라지지 않고, 여전히 제대로 값을 반환되고 있는 것을 볼 수 있습니다.

위에서 말했던 환경을 기억한다는 말이 이거 같습니다. 내부 함수는 text를 어디서 받아왔는지 기억을 해 outerFunc함수의 실행이 끝나고 text를 찾게 되는것이지요.


다른 예를 또 보겠습니다. 여러 블로그를 보면 대표적으로 많이 있는 예제로 적당한 예시가 될거 같습니다.

var base = 'Love';
function sayLove(name) {
    var text =base + name;
    return function() {
        console.log(text);
    }
}
var hello1 = sayLove('건우')
var hello2 = sayLove('단비')
var hello3 = sayLove('단단')
hello1()	//Love건우
hello2()	//Love단비
hello3()	//Love단단

출력 결과를 보시면 text변수가 sayLove의 입력값에 따라 변화하고 있는 것 처럼 보이게 됩니다. 실제로는 외부 함수인 sayLove의 변수 text가 여러번 생성된것입니다. 즉 hello1, hello2, hello3는 서로 다른 환경을 갖고 있게 됩니다.


정보은닉

자바와 같은 몇몇 언어들은 메소드를 프라이빗으로 선언할 수 있는 기능을 제공합니다. 같은 클래스 내의 다른 메소드에서만 그 메소드를 호출할 수 있다는 의미를 합니다. 쉽게 말해 같은 함수안에서만 값은 변경할수 있고 외부에서 직접적으로 변경할 수 없다는 말 입니다. 아래 예제를 보겠습니다.

function PersonName(name) {
    this._name = name
}

PersonName.prototype.say = function() {
    console.log('유저의 이름은, ' + this._name)
}

var personName1 = new PersonName('건우');
var personName2 = new PersonName('단비');
var personName3 = new PersonName('단단');

personName1.say(); // 유저의 이름은, 건우
personName2.say(); // 유저의 이름은, 단비
personName3.say(); // 유저의 이름은, 단단
personName1._name = '철수';
personName1.say(); // 유저의 이름은, 철수

위 PersonName함수에 name값을 받고 선언할수 있게 됩니다. PersonName을 prototype.say 메소드를 선언해 유저의 이름을 console로 찍어주는 메소드를 작성했습니다. 코드 아래 결과를 보면 personName1 = new PersonName('건우')가 실행되면 PersonName함수 매개변수name에 '건우'가 들어가게 됩니다. personName1.say()로 메소드를 실행시키게 되면 say메소드 안에 console.log가 실행돼 값이 출력되게 됩니다.
근데 여기서 이름은 함부로 마음대로 변경해서는 안되는 값인데 personName1._name= '철수' 라고 입력하게 되면 personName1.say()메소드를 다시 실행시키면 이전과 다른 결과가 나오게 됩니다. 클로저를 사용하지 않는다면 여전히 외부에서 쉽게 접근할 수 있는 변수가 되게 됩니다.


클로저로 정보은닉 하기

이 경우 클로저를 활용하여 외부에서 함수 내 변수에 접근할 수 없도록 했습니다.

function PersonName(name) {
    var _name = name;
    return function() {
        console.log('유저의 이름은,' +name)
    }
}



var personName1 = PersonName('건우');
var personName2 = PersonName('단비');
var personName3 = PersonName('단단');

personName1(); // 유저의 이름은, 건우
personName2(); // 유저의 이름은, 단비
personName3(); // 유저의 이름은, 단단

personName1,2,3 모두 PersonName함수에 매개변수를 받고 변수에 저장합니다. 해당 변수는 클로저인 PersonName의 내부함수를 포함하고 있고, 그 때 클로저의 특징인 만들어진 환경을 기억하게 되어 외부함수인 PersonName의 변수 _name을 이용해 console.log에 값을 출력하게 됩니다. 이때 별도의 인터페이스를 제공하지 않는다면 해당 함수의 _name변수에 접근할 방법이 전혀 없게 됩니다.

0개의 댓글