스코프와 클로저..

현채은·2023년 3월 5일
0
post-thumbnail

클로저.. 너무 어렵다 🔥
그래서 이건 꼭 기록으로 남겨두어야겠다고 생각이 들었다 !

스코프 ( scope )

  • 전역변수 : 자바스크립트 가장 바깥범위에 선언한 변수 ( window 객체에 변수를 만드는 것 )
    ➡️ 최대한 지양하는 것이 좋다..
  • 지역변수 : 함수 안에 들어있는 변수 ( 해당함수 내에서만 사용 가능 )
    ➡️ 지역변수는 전역변수에 영향을 끼치기 힘들다 ..

EX 1.

 let x = 'global';
function ex() {
  x = 'change';
}
ex();
console.log(x); // 'change'

➡️ 위 코드에서 전역변수의 x값이 change로 변경 되었다 .

🧚‍♀️ 왜 ?

함수 ex()안에서 전역변수 x의 값을 재할당해주었기 때문에 (새로선언 X )

EX 2.

 var x = 'global';
function ex() {
  var x = 'local';
  x = 'change';
}
ex(); // x를 바꿔본다.
console.log(x); // 여전히 'global'

➡️ 위 코드에서 전역변수의 x값이 global로 유지되었다 .

🧚‍♀️ 왜 ?

함수 ex( )안에서 지역변수 x를 새로 선언했기 때문에 ( let )
( 함수 스코프 내에 변수 x가 선언되어 있기 때문에 )
➡️ 전역스코프에 있는 x의 값에 스코프 체인을 통해 도달하지 않았음
➡️ ex( ) 함수스코프 에서만 x = 'change'
➡️ ex( ) 함수스코프 외부에서 x = 'global'

스코프 체인 ( scope chain )

  • 내부함수에서 외부함수로의 접근 ? ➡️ OK
  • 외부함수에서 내부함수로의 접근 ? ➡️ NO
  • 1️⃣ 자신의 스코프 내에서 변수를 찾기
    2️⃣ 상위 스코프에서 변수 찾기
    3️⃣ 전역 스코프에서 변수 찾기
    ➡️ 이게 바로 스코프 체인의 원리 !!

렉시컬 스코핑 ( lexical scoping )

  • 스코프는 함수 호출시 생성되는 것이다 ? ➡️ NO ❌❌❌❌❌
  • 스코프는 함수 선언시 생성되는 것이다 ? ➡️ YES ⭕️⭕️⭕️⭕️⭕️
var name = 'zero';
function log() {
  console.log(name);
}

function wrapper() {
  name = 'nero';
  log();
}
wrapper(); // 'nero'

🧚‍♀️ 왜?

log( ) 내의 name은 전역스코프 name을 가리키는 것임 !
➡️ log( )는 wrapper( ) 함수스코프 내에서 호출 되었지만 선언 된 것은 전역스코프임

하지만 ❗️

➡️ wrapper ( ) 내부에서 변수 name의 값을 'nero'로 재할당 해줌

var name = 'zero';
function log() {
  console.log(name);
}

function wrapper() {
  var name = 'nero';
  log();
}
wrapper(); // 

🧚‍♀️ 왜?

log( ) 내의 name은 전역스코프 name을 가리키는 것이기 때문에 !
➡️ log( )는 wrapper( ) 함수스코프 내에서 호출 되었지만 선언 된 것은 전역스코프임

하지만❗️

➡️ wrapper ( ) 내에서 let으로 선언 된 name 은 해당 함수 내에서만 사용할 수 있는 지역변수임
➡️따라서, log ( )에서의 name은 상위스코프인 전역에서 선언 된 name = 'zero'를 반환할 수 밖에 없음 !

클로저 ( closure )

: 함수와 그 주변함수 상태의 주소집합
( 함수와 그 함수가 접근할 수 있는 변수의 조합 , 해당함수에서 사용할 수 있는 변수들 )

  • 자신을 포함하고 있는 외부함수보다 내부함수가 더 오래 유지되는 경우,
    ➡️ 외부 함수 밖에서 내부함수가 호출되더라도 외부함수의 지역 변수에 접근할 수 있는 함수
  • 자신이 생성될 때의 환경(Lexical environment)을 기억하는 함수
 function outerFunc() {
  var x = 10;
  var innerFunc = function () { console.log(x); };
  innerFunc();
}

outerFunc(); // 10
  • 함수 outerFunc 내에서 내부함수 innerFunc가 선언되고 호출되었음
  • 내부함수 innerFunc는 자신을 포함하고 있는 외부함수 outerFunc의 변수 x에 접근가능 ( 여기서 변수 x는 자유변수 )
  • 렉시컬 스코핑(Lexical scoping) 의 개념을 되짚어보자 !
    • innerFunc는 함수 outerFunc의 내부에서 선언
    • 함수 innerFunc의 상위 스코프는 함수 outerFunc
    • 만약 함수 innerFunc가 전역에 선언되었다면 ?
      ➡️ 함수 innerFunc의 상위 스코프는 전역 스코프
    • 함수 innerFunc는 자신이 속한 렉시컬 스코프
      (전역, 함수 outerFunc, 자신의 스코프)를 참조 ( for. 스코프체인 )
    • 🌟 상위 스코프에 접근할 수 있는 것 ➡️ 렉시컬 스코프의 레퍼런스를 차례대로 저장하고 있는 실행 컨텍스트의 스코프 체인자바스크립트 엔진이 검색하였기에 가능한 것
    • ex>
      ➤ innerFunc 함수 스코프(함수 자신의 스코프를 가리키는 활성 객체) 내에서 변수 x를 검색한다. 검색이 실패하였다.
      ➤ innerFunc 함수를 포함하는 외부 함수 outerFunc의 스코프에서 변수 x를 검색한다. 검색이 성공하였다. ( 참조 )
      ▷ 만약 외부함수 outerFunc의 스코프에도 변수 x가 없다면 전역 스코프에서 검색 ➡️ 전역 스코프에도 없다면 변수를 찾을 수 없다는 에러 발생.
      ( undefined가 아니다 ! )
  • return으로 innerFunc를 반환한 경우
function outerFunc() {
  var x = 10;
  var innerFunc = function () { console.log(x); };
  return innerFunc;
}

/**
 *  함수 outerFunc를 호출하면 내부 함수 innerFunc가 반환된다.
 *  그리고 함수 outerFunc의 실행 컨텍스트는 소멸한다.
 */
var inner = outerFunc();
inner(); // 10
  • 위 코드에서 스코프 함수 ➡️ innerFunc ( )
  • 함수 outerFunc는 내부함수 innerFunc를 반환하고 생을 마감
    ➡️ 그런데 어떻게 outerFunc에서 정의된 변수를 사용할 수 있을까 ?
  • 클로저는 반환된 내부함수가 자신이 선언됐을 때의 환경(Lexical environment)인 스코프를 기억하여 ⭐️ 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수

참고 : https://poiemaweb.com/js-closure

profile
프론트엔드 개발자

0개의 댓글