var는 한번 선언된 변수를 다시 선언할 수 있다.
let name = 'Mike';
let name = 'Jane';
console.log(name) //error!
var name = 'Mike';
var name = 'Jane';
console.log(name) //Jane
var는 선언하기 전에 사용 가능하다.
var로 실행한 모든 변수는 최상위로 끌어올려진것 처럼 동작한다.(=호이스팅)
그러나 여기서 콘솔은 undefined가 나오는데, 선언은 호이스팅 되지만 할당은 호이스팅되지 않기 때문. 그래서 error가 아닌 undefined가 나온다.
var name; //선언
console.log(name); //undefined
name = 'Mike'; //할당
호이스팅 : 스코프 내부 어디서든 변수 선언은 최상위에 선언된 것처럼 행동하는 것.
let은 같은 상황에서 에러를 내는데, 이는 Temporal Dead zone과 관련이 있다.

let과 const는 TDZ의 영향을 받는다. 할당을 하기 전에는 사용할 수 없기 때문. 이는 코드를 예측가능하게 하고 잠재적인 버그를 줄일 수 있다.
호이스팅은 스코프 단위로 일어난다.
스코프는 변수이름, 함수 이름, 클래스 이름과 같은 식별자가 본인이 선언된 위치에 따라 다른 코드에서 자신이 참조될 수 있을지 없을지 결정되는 유효범위이다.
변수가 전역에서 선언된다면 전역스코프, 지역에서 선언된다면 지역스코프를 갖게된다.
var은 함수 스코프, let과 const는 블록스코프이다.
블록스코프 : 모든 코드블록에서 선언된 변수는 코드블록 내에서만 유효하며 외부에서는 접근할 수 없다. 여기서 코드블록 = 함수, if문, for문, while문, try/catch문 등
함수스코프 : 함수 내에서 선언된 변수만 그 지역변수가 된다.
const age = 30;
if(age>19){
var txt = '성인';
}
console.log(txt);//'성인'
위와 같이 var은 if문 밖에서도 사용 가능하지만, let과 const는 중괄호 밖에서 사용 불가능하다. var도 마찬가지로 함수 내에서 선언되면 밖에서 사용 불가능하다.
함수 내부에 함수가 중첩되어있을때 계층적인 구조가 형성되는데, 이렇게 물리적으로 존재하는 스코프 계층을 스코프 체인이라고 한다.

주의할것! 참조할 스코프는 위(부모)로만 올라간다. 즉, 마지막 라인의 y는 전역스코프에서 참조 가능한 값이 없기 때문에 내려가서(자식) 찾는 대신 Reference error가 나온다. (=스코프 체인의 단방향성)
자바스크립트는 정적스코프(=렉시컬 스코프)이다. 함수는 호출됐을때가 아닌, '태어나는 동시에' 본인의 내부슬롯에 상위스코프에 대한 참조를 저장한다.

위 코드에서 outer함수가 ella에 할당되면서 생명주기가 마감되었는데 어떻게 불러올 수 있을까?
마감된 외부함수의 지역변수 x를 inner가 참조 가능한데, 이때 inner를 closure라고 한다.
ella는 inner 함수 객체를 참조하고, inner객체는 내부슬롯의 outer 렉시컬 환경을 참조하기 때문에, garbage collection의 대상이 되지 않는다.

정리 :
1. 한 함수가 상위스코프의 식별자를 참조하고 있고,
2. 본인의 외부함수보다 더 오래 살아있다면
이 중첩함수는 클로져이다.

let과 function에서 선언한 변수들 모두 lexical 환경으로 올라가며 시작한다.



1. 처음 전역 어휘적 환경에는 makeAdder:function, add3:function이 들어간다.
2. const add3 = makeAdder(3)을 실행하면 x:3이 makeAdder 레벨의 어휘적 환경에 들어간다.
3. add3(2)를 실행하면 익명함수의 어휘적환경에 y:2가 들어간다.
4. add3()함수가 생성된 이후에도 상위함수인 makeAdder의 x에 접근이 가능하다.

전역환경 - makeCounter : function
makeCounter단위 어휘적환경 - num:0
익명함수 어휘적환경 - ' ':function
counter함수가 생성된 이후에도 상위함수인 makeCounter()의 num에 접근이 가능하다. 내부함수에서 외부함수의 num에 접근하여 값을 업데이트 한다.
num = 0 -> 1 -> 2 -> 3 ->...
++
https://joshua1988.github.io/web-development/javascript/function-expressions-vs-declarations/
이거 이해하기!
출처 : https://www.youtube.com/watch?v=PVYjfrgZhtU
https://www.youtube.com/watch?v=4_WLS9Lj6n4