클로저(Closure)

BaeSeong-min·2024년 12월 30일
0

ES6 문법공부

목록 보기
11/22
post-thumbnail

📙ES6 문법공부


📌클로저

✨어휘적 환경(Lexical Enviroment)

자바스크립트는 어휘적 환경을 갖는다.

💡코드에 흐름에 따른 어휘적 환경의 변화 예시1

코드가 실행되면 변수 선언문과 함수 선언문이 호이스팅 된다. 따라서 makeAdder 함수와 add3 변수가 전역 Lexical 환경에 올라간다. 호이스팅 된 변수와 함수가 전역 Lexical 환경에 저장된다. 호이스팅된 변수 one은 초기화가 되지 않았기에 현재 사용할 수 없다. 반면, 함수 선언문은 선언과 초기화가 동시에 이루어지며 함수 이름과 함수 정의가 메모리에 저장된다. 즉, 호이스팅 과정에서 함수 선언문의 전체가 메모리에 저장되기에 함수 선언문으로 정의된 함수는 어디서든 호출 가능하다.

전역 Lexical 환경

one : 초기화 X (사용 불가)

addOne : function (사용 가능)

✏️ 호이스팅이란

  • 코드를 실행하고 첫 번째 코드를 실행시키기 전에, 변수 선언과 함수 선언이 메모리에 저장되는 것이다. 참조 사항으로 함수 표현식과 익명 함수는 호이스팅 안 된다.


let one;이라는 실제 코드를 만나면 Lexical 환경에 저장된 변수 one에 undefined가 할당된다. 변수 one에 undefined를 할당하여 초기화되었기 때문에 이제 one을 사용할 수 있다.

전역 Lexical 환경

one : undefined (사용 가능)

addOne : function

✏️ 함수 선언문 vs 함수 표현식

함수 선언문함수 표현식
함수 이름과 함수 정의가 호이스팅된다.함수 자체는 호이스팅되지 않는다.
함수 선언문 위에서도 호출 가능하다.함수가 할당된 변수만 호이스팅되며, 변수 초기화는 실제코드를 만났을 때 이루어진다.
  • 함수 선언문 예제

sayHello(); // "Hello, world!"
function sayHello() {
  console.log("Hello, world!");
}

// 함수 선언문 = 함수 이름 + 함수 정의이며, 이를 간단히 함수라고 부르는 것도 가능하다.
  • 함수 표현식 예제

console.log(sayHi); // undefined
sayHi(); // TypeError: sayHi is not a function
var sayHi = function () {
  console.log("Hi!");
};


one = 1;을 통해서 one이라는 변수에 숫자 1이 할당되었다.

전역 Lexical 환경

one : 1

addOne : function

addOne 함수 선언문은 이미 호이스팅되어 메모리에 저장되었으므로, 함수 선언문은 건너뛰고 addOne(5); 코드부터 실행이 가능하다. 함수 호출과 동시에 새로운 Lexical 환경이 만들어진다. 참고로 전역 Lexical 환경을 제외한 나머지는 모두 내부 Lexical 환경이라 한다.

내부 Lexical 환경

num : 5

함수의 Lexical 환경에는 함수가 넘겨받은 매개변수와 지역변수가 저장된다. 코드에서 변수를 찾을 때, 내부 Lexical 환경에서 찾아본 후 없으면, 외부 Lexical 환경을 찾아본다. 외부에도 없다면 전역 Lexical 환경에서 변수를 찾아본다. 내부 Lexical 환경에 num 변수는 저장되어 있지만, one이라는 변수는 없다. 따라서 전역 Lexical 환경을 참조해서 변수 one을 찾았고 함수 안의 코드를 실행한다.

내부 Lexical 환경 -> 외부 Lexical 환경 -> 전역 Lexical 환경

이렇게 범위를 넓혀가며 변수를 찾는다.

💡코드에 흐름에 따른 어휘적 환경의 변화 예시2


코드가 실행되면 변수 선언문과 함수 선언문이 호이스팅 된다. 그리고, makeAdder 함수와 add3 변수가 전역 Lexical 환경에 저장된다.

전역 Lexical 환경

makeAdder : function

add3 : 초기화X (사용 불가)


makeAdder 함수가 호출되면서 makeAdder Lexical 환경이 만들어진다. makeAdder Lexical 환경에는 매개변수로 전달받은 변수 x가 저장된다. 또한, add3 변수에 값을 할당하는 실제 코드를 만났으므로, add3는 함수로 초기화되어 사용 가능해진다.

makeAdder Lexical 환경

x : 3

전역 Lexical 환경

makeAdder : function

add3 : function

마지막 줄을 실행하면, add3 함수가 호출되고 따라서 새로운 익명함수 Lexical 환경이 생성된다. 이처럼, 함수가 호출될 때마다 새로운 Lexical 환경이 생성된다. 익명함수 Lexical 환경에는 매개변수로 전달받은 변수 y가 저장된다. 이때, 함수를 실행하면서 x + y 연산을 수행하기 위해 변수 y를 내부 Lexical 환경에서 찾는다. 반면, 변수 x는 내부 Lexical 환경에 저장되어 있지 않기에 외부 Lexical 환경 (makeAdder Lexical 환경)을 참조한다. 해당 Lexical 환경에 변수 x가 저장되어 있기에 해당 변수를 참조하여 연산을 수행한다.

익명함수 Lexical 환경

y : 2

✨클로저(Closure)

함수와 그 함수의 렉시컬 환경의 조합이다. 함수가 생성될 당시의 외부 변수(외부함수가 사용한 변수)를 기억하고, 생성된 함수가 호출될 때마다 그 변수들을 참조하여 계속 사용할 수 있게 한다는 개념이다.

※ 함수가 생성된다는 말은 어떤 변수에 함수가 할당되는 것을 의미한다.

💡클로저를 이용한 은닉화

function makeCounter() {
  let num = 0; // 은닉화
  
  return function() {
    return num++;
  }
}

let counter = makeCounter();
console.log(counter()); // 0
console.log(counter()); // 1
console.log(counter()); // 2

counter 함수가 생성된 이후에 외부변수 num을 기억하고 있는 것이다. 따라서 counter 함수를 호출할 때마다 외부변수 num을 참조하여 사용할 수 있다. 이것이 클로저라는 개념이다.

위 코드에서 num 값은 은닉화(encapsulation)되어 있다. 다시 말해, counter 함수를 통해서만 num 값을 1씩 증가시키고 그 값을 반환할 수 있다. 외부에서 num 값을 직접 수정할 수 없으므로 num의 값을 특정한 값으로 설정한다거나 갑자기 값을 10씩 증가시키는 것과 같은 활동은 불가능하다. 실제로 makeCounter 함수는 사용자가 직접적으로 볼 수 없고, counter() 함수만을 사용하게끔 하여 num 값을 안전하게 관리한다.

profile
성민의 개발 블로그 🔥

0개의 댓글