책 인사이드 자바스크립트의 내용을 참고하였습니다.

내부 함수 (inner function)와 스코프 체이닝

function init(){
  var name = "Mozila';
  function displayName(){
    alert(name);
 }
  displayName();
}
init();
  • 특정 함수 안에 위치한 함수를 내부함수라고 한다. 여기서는 displayName이 내부함수이다.
  • displayName은 내부 함수이기 때문에 init() 함수 내에서만 사용이 가능하고 내부 함수는 자신을 둘러싸고 있는 외부 함수의 변수에 접근이 가능하다. 자바스크립트의 스코프 체이닝의 개념이다.

클로져 Closure

function makeFunc(){
  var name = 'Mozila';
  function displayName(){
   alert(name);
  }
  return displayName;
}
var myFunc = makeFunc();
myFunc();
  • displayName을 makeFunc 함수 외부에서 호출하려면 어떻게 해야할까? 함수를 return 하면 외부에서의 호출이 가능해진다.
    여기서 🌟포인트🌟는 displayName 함수의 참조값을 가지게된 myFunc 함수를 실행하면 이미 호출이 끝난 makeFunc의 지역변수 name 값을 사용한다는 것이다.
  • 몇몇 프로그래밍 언어에서 함수 안의 지역 변수는 함수가 실행되는 동안에만 존재한다. 때문에 makeFunc의 실행이 끝나면, name 변수는 더 이상 존재하지 않는다고 생각할지도 모르지만 자바스크립트 코드는 흐름대로 잘 동작한다.

이는 함수가 Closure를 만들기 때문이다.

이미 생명 주기가 끝난 외부 함수의 변수를 참조하는 함수를 클로져라고 한다. 여기서는 이미 실행이 끝난 makeFunc의 name 변수를 참조하는 displayName 함수가 클로저가 된다.

makeFunc의 실행 컨텍스트는 사라졌지만, makeFunc의 변수 객체는 여전히 남아있고 displayName의 스코프체인으로 참조되고 있다.

클로저란 함수와 함수가 선언된 곳의 lexical environment을 모두 포함한 곳이다. 이 environment는 closure가 만들어진 시점에 스코프 안에 있던 모든 local varible들로 이루어져 있다. 이 경우의 myFunc은 makeFunc이 실행되었을 때 만들어진 displayName의 인스턴스를 참조하고 있다.
displayName의 인스턴스는 변수 name이 존재하는 자신의 lexical environment에 대한 참조를 유지한다. 이 이유로 myFunc이 호출되었을 때 name 변수가 Mozila 값을 alert에 전달해줄 수 있는 것이다.

{ } 로 const 감싼 경우

{
    const name = "Alan"
}
console.log(name);
// Uncaught ReferenceError: name is not defined 

name이 정의되지 않았다는 오류가 발생한다.
변수나 constant의 범위(Scope)가 뜻하는 바는 해당 변수가 어느 범위까지 접근이 가능한지 나타낸다.

🔒 let, const 와 { }

let이나 const 로 선언한 변수는 변수가 정의 되어 있는 블록 , { } 안에서만 접근이 가능하다. 따라서 2) 에서의 console.log가 실행되는 전역 스코프에서는 name 변수를 찾을 수 없는 것이다.

function start(){
const message = "hi";
  if(true){
    const another = 'bye';
}
console.log(another)
}

함수, if, for 문 모두 { }으로 구성 되어 있다. 위 코드의 if 문 내에서 정의된 another 변수도 if 밖을 벗어나지 못하기 때문에 아래 console.log(another) 은 ReferenceEffor에러를 낸다.

✔️ 전역변수는 프로그램 내 어디에서든지 접근이 가능하고 수정할 수 있기 때문에 각종 버그나 문제를 일으킬 수 있다. 따라서 전역 변수는 최대한 만들지 말아야한다.

참고