I. 렉시컬(정적) 스코프 lexical(static) scope
- 변수나 상수가 코드상 어디에서 지정되었는가에 따라 그 사용 범위를 결정
- 함수가 코드상 어디에서 정의되었는가에 따라 그 상위 스코프를 결정
- 호출한 곳을 기준으로 하는 동적 스포크 dynamic scope 와 상반되는 개념
- 👉 MDN 문서 보기
const x = 1;
const y = 1;
const z = 1;
function func1 () {
const y = 2;
const z = 2;
console.log('2', x, y, z);
func2();
}
function func2 () {
const z = 3;
console.log('3', x, y, z);
}
console.log('1', x, y, z)
func1();
- func2을 호출한 블록에서의 y 값은 2
- func2을 정의된 블록에서의 y 값은 1
- 정의된 블록을 기준으로 상위 스코프의 값이 사용됨
💡 func2를 func1 안으로 옮기면
const x = 1;
const y = 1;
const z = 1;
function func1 () {
const y = 2;
const z = 2;
function func2 () {
const z = 3;
console.log('3', x, y, z);
}
console.log('2', x, y, z);
func2();
}
console.log('1', x, y, z)
func1();
II. 렉시컬 환경 lexical environment
- 전체 문서, 함수, 블록을 실행하기 전 만들어지는 내부 객체
- 각 스코프의 고유 값들과 외부 스코프에 대한 참조를 포함
구성요소
- 환경 레코드 environment record - 해당 스코프의 데이터들
- 외부 렉시컬 환경에 대한 참조 outer lexical environment reference
const x = 1;
const y = 1;
const z = 1;
function func1 (a) {
const y = 2;
const z = 2;
function func2 (b) {
const z = 3;
console.log('3', x, y, z, b);
}
console.log('2', x, y, z, a);
func2(a + 1);
}
console.log('1', x, y, z)
func1(1);
III. 클로저 closure
function func1 () {
const word = 'Hello';
function func2 () {
console.log(word);
}
return func2;
}
const logHello = func1();
logHello();
- logHello에는 func1 안의 함수인 func2가 반환되어 지정됨
- func1의 실행이 끝났음에도 불구하고, 해당 스코프 내의 값이 살아 있음
- func2와 func2가 선언된 환경(func1의 스코프)의 조합 - 클로저
function createCounter (start) {
let num = start;
return function () {
console.log(++start);
return start;
}
}
const count = createCounter(10);
- 단지 값을 복사해서 갖는 것이 아니라, 해당 값이 저장되는 외부 환경 자체가 유지됨
⭐️ private field 흉내내기
function employeeCreator (name, age) {
let _name = name;
let _age = age;
return {
name: () => _name,
age: () => _age,
setAge: function (age) { _age = age; },
getOlder: function (years) { _age += years; }
}
}
const employee = employeeCreator('홍길동', 20);
console.log(employee);
console.log(employee.name(), employee.age());
employee.setAge(25);
console.log(employee.name(), employee.age());
employee.getOlder(3);
console.log(employee.name(), employee.age());