전역과 지역 스코프
전역 : 코드의 가장 바깥 영역을 말하며 전역은 '전역 스코프'를 만든다.
전역에 변수를 선언하면 전역 스코프를 갖는 전역 변수가 되며 전역 변수는 어디서든 참조 가능하다.
지역 : 함수 내부 몸체를 말하며 지역은 '지역 스코프'를 만든다.
지역에 변수를 선언하면 지역 스코프를 갖는 지역 변수가 되며, 자신의 지역 스코프와 하위 지역 스코프에서 유효하다.
var x = 'global x';
var y = 'global y';
function outer () {
var z = "outer's local z";
console.log(x); // global x
console.log(y); // global y
console.log(z); // outer's local z
function inner () {
var x = "inner's local x";
console.log(x); // inner's local x
console.log(y); // global y
console.log(z); // outer's local z
}
inner();
}
outer();
console.log(x); // global x
console.log(y); // global y
console.log(z); // ReferenceError: z is not defined
// 하위 스코프에서 유효한 변수는 상위 스코프에서 참조 불가능

스코프 체인
전역 스코프 (x, y, outer) <- outer 지역 스코프 (z, inner) <- inner 지역 스코프 (x)
자바스크립트 엔진은 변수를 참조할 때 스코프 체인을 통해 변수를 참조하는 코드의 스코프에서 시작하여
상위 스코프 방향으로 이동하며 선언된 변수를 검색한다.
=> 상위 스코프에서 유효한 변수는 하위 스코프에서 자유롭게 참조 가능, 하위 스코프에서 유효한 변수는 상위 스코프에서 참조 불가능
함수 레벨 스코프
C, Java 등 대부분의 프로그래밍 언어는 함수 몸체만이 아니라 모든 코드 블록(if, for, while, try/catch 등)이 지역 스코프를 만드는 "블록 레벨 스코프"를 가진다.
var키워드로 선언 된 변수는 오로지 함수의 코드 블록만을 지역 스코프로 인정하는 "함수 레벨 스코프"를 가진다.
// i는 전역 변수
var i = 0;
// 전역 변수로 이미 선언 된 i가 중복 선언 된다.
for(var i = 0; i < 10; i++) {}
// for 코드 블럭 내부의 값 변화가 반영된다.
console.log(i);
var의 문제점
ES5까지 변수를 선언할 수 있는 유일한 방법은 var 키워드를 사용하는 것이었는데 이는 몇가지 문제를 유발한다.
// 1. 변수 중복 선언
var msg = "안녕하세요";
console.log(msg); //출력 : 안녕하세요
// var 키워드로 선언 된 변수는 같은 스코프 내에서 중복 선언이 허용 된다.
// 초기화 문이 있는 변수 선언문은 자바스크립트 엔진에 의해 var 키워드가 없는 것처럼 동작한다.
var msg = "안녕히가세요"; //출력 : 안녕히가세요
console.log(msg);
// 초기화 문이 없는 변수 선언문은 무시 된다.
var msg;
console.log(msg); //출력 : 안녕히가세요
// 2. 함수 레벨 스코프
// 함수 외부에서 var 키워드로 선언한 변수는 코드 블록 내에서 선언해도 모두 전역 변수가 된다.
var i = 0;
for(var i = 0; i < 10; i++) {}
console.log(i);
// 3. 변수 호이스팅
// 변수 선언문이 스코프의 선두로 끌어올려진 것 처럼 동작한다.
// 변수 선언문 이전에 참조 할 수 있다.
console.log(test); // 출력 : undefined
test = "반갑습니다";
console.log(test); // 출력 : 반갑습니다.
var test;
var 키워드의 단점을 보완하기 위해 ES6에서는 새로운 변수 선언 키워드인 let, const를 도입했다.
let : 선언, 초기화 분리되어 동작
var : 선언, 초기화 동시
// 1. 변수 중복 선언 금지
let msg = "안녕하세요";
// 같은 스코프 내에서 중복 선언을 허용하지 않는다.
// let msg = "안녕히가세요";
// 2. 블록 레벨 스코프
// 모든 코드 블록을 지역 스코프로 인정한다.
let i = 0;
for(let i = 0; i < 10; i++) {
console.log(`지역 변수 i : ${i}`);
}
console.log(`전역 변수 i : ${i}`);
// 3. 변수 호이스팅
// 변수 호이스팅이 발생하지 않은 것처럼 동작한다.
// var : 선언, 초기화 동시
// let : 선언, 초기화 분리되어 동작, 초기화되기 전에 사용이 불가능
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x;
let 키워드에서 알아본 특징은 모두 동일하며
상수(const) 선언에서 사용 된다는 점이 특징이다.
const : 선언과 동시에 초기화 해야한다.
let : 선언, 초기화 분리되어 동작
var : 선언, 초기화 동시
//const 키워드로 선언한 변수는 반드시 선언과 동시에 초기화 해야 한다
// const x;
const x = 1;
// const 키워드로 선언한 변수는 재할당 금지
// x = 2; TypeError: Assignment to constant variable.
// 일반적으로 상수의 이름은 대문자로 선언해 상수임을 나타내며, 여러 단어로 이루어진 경우
// _(언더스코어)로 구분해서 스네이크 케이스로 표현하는 것이 일반적이다.
const DISCOUNT_RATE = 0.15;
// const 키워드로 선언 된 변수에 객체를 할당한 경우 프로퍼티 값을 변경할 수 있다.
const student = {
name : '홍길동',
age : 20
};
student.name = '유관순';
console.log(student);
// 객체 재할당은 불가능하다.
// student = {}; TypeError: Assignment to constant variable.