JavaScript 스코프와 클로저(Closure)의 개념

zaman·2022년 8월 11일
1

Javascript | Basics

목록 보기
4/8
post-thumbnail

🚧 스코프?

:자바스크립트를 포함한 모든 프로그래밍 언어에서 가장 기본적이고 중요한 개념 중 하나로 변수 이름, 함수 이름, 클래스 이름과 같은 식별자가 본인이 선언된 위치에 따라 다른 코드에서 자신이 참조될 수 있을지 없을지 결정되는 것을 의미함

예시 코드

function add(x,y) {
  	console.log(x, y); // 3 6
  	return x+y;
}

add(3,6);

console.log(x,y); // error

➡️ 자신이 선언된 위치에 따라 유효 범위가 결정된 것을 확인할 수 있음

👫 함수의 중첩


함수는 위의 이미지처럼 중첩될 수 있는데 순서대로 전역함수 - 외부함수 - 중첩함수가 있음

함수가 중첩된다
➡️ 각 함수의 지역 스코프도 중첩
➡️ 중첩에 의해 계층적 구조를 가질 수 있다

아래의 예를 통해 다시 확인하자

var a = "나는 글로벌";

function outer() {
  var b = "나는 outer의 지역변수";
  console.log(a); // 나는 글로벌
  console.log(b); // 나는 outer의 지역변수

  function inner() {
    var a = "나는 inner의 지역변수";
    console.log(a); // 나는 inner의 지역변수
    console.log(b); // 나는 outer의 지역변수
  }

  inner();
}

outer();
console.log(a); // 나는 글로벌
console.log(b); // err

어떻게 이런 결과가 나왔을까?

전역 스코프
x:나는 글로벌, outer: func obj

   	👆 : outer에도 없으면 하나 위로
    
outer의 지역 스코프
y: 나는 outer의 지역변수, inner: func obj

   	👆: inner에 변수가 없으면 하나 위로
    
inner의 지역 스코프
x: 나는 inner의 지역변수

➡️ 전역에도 없다! ➡️ 레퍼런스 에러

🪜 스코프 레벨

  • 블록 레벨 스코프 - if, for 문, 함수 ... ➡️ 대부분 프로그래밍 언어
  • 함수 레벨 스코프 - only 함수 ➡️ js
    js도 블록레벨 스코프가 필요해 ➡️ let, const(es6)
  • 동적 스코프: 함수가 어디서 호출되는지에 따라 동적으로 상위 스코프 결정
    (런타임 도중 실행컨텍스트나 호출 컨텍스트에 의해 결정)
  • 정적 스코프 === 렉시컬 스코프: 함수가 정의되는 시점에 상위 스코프 결정
    ➡️ js

그렇면 이제 함수 호출과정을 다시 살펴보자

함수 호출 ➡️ 실행 컨텍스트 생성 ➡️ 렉시컬 환경 생성 ➡️ 실행 ➡️ 실행 컨텍스트에서 pop() 제거
(렉시컬 환경: 어떤 코드가 어디서 실행되고 본인 주변에 어떤 코드들이 있는지 대체적인 정보를 담고 있는 환경)

const x = 1;

function outer() {
  const x = 10;
  const inner = () => {
    console.log(x);
  };

  return inner;
}

const guess = outer();

guess();  // 10

위의 코드를 보면 콘솔에 10이 찍히는걸 확인할 수 있는데 아까 함수가 실행 완료되면 실행 컨텍스트에서 pop된다고 하지 않았나??
그럼 어떻게 10이 출력된걸까??

이것을 이해하기 위해 필요한 개념이 클로저이다

🔒 클로저!

: 함수와 함수가 선언된 어휘적 환경의 조합으로 하나의 state가 의도치 않게 변경되지 않도록 state를 안전하게 은닉하고 특정 함수에게만 state변경을 허락하게 해줌

  • 중첩함수가 상위 스코프의 식별자를 참조
  • 본인의 외부함수보다 더 오래 유지되는 경우

위의 예처럼 외부함수의 변수를 참조하고 외부함수보다 더 오래 유지된다면 이런 중첩함수를 클로저라고한다!
외부함수: outer
중첩함수: inner
참조변수(자유변수): x

outer 함수는 실행컨텍스트 스택에서 완전히 제거가 되었지만 렉시컬 환경에서까지 제거되진 않음

guess는 inner 함수 객체를 참조하고 있고 inner 객체는 본인의 내부 슬롯에 저장된 outer 함수의 렉시컬 환경을 참조 따라서 삭제 대상이 되지 않음
➡️ 따라서 변수 x 다시 참조 가능!

생명을 마감하고 실행 컨텍스트에사 사라졌지만 내부 슬롯에 저장된 상위 스코프에 의존하여 상위 스코프 내 식별자 참조 가능하게 된 것!

profile
개발자로 성장하기 위한 아카이브 😎

0개의 댓글