-
Notes from reading 🔖 You Don't Know JS Yet - 8JavaScript 2025. 12. 27. 17:11
### 파트 2 - chapter 3 스코프 체인
- 스코프와 중첩 스코프 사이에 맺어진 연결 -> 스코프 체인
- 변수 접근 시 스코프 체인을 기반으로 변수를 찾는데, 위/밖으로만 찾음
- 렉시컬 스코프는 컴파일 초기에 확정 -> 런타임에서는 이미 정해진 렉시컬 스코프를 활용하여 변수를 탐색한다
- 런타임에 찾지 않기에, 효율적 👽
- 다만, 런타임에 다른 프로그램이 변수를 전역에 선언할 가능성 등이 있기에, 런타임 도중에 스코프가 정해지는 경우도 있다
- 따라서 완전히 확정되는 것은 런타임중이긴 함
- 이름은 같은 두 개의 변수가 하나의 스코프에 동시에 존재할 수는 없다
- 같은 이름의 변수를 굳이 사용하고자 한다면, 스코프를 분리해야 한다
- 변수를 찾는 순서는 현재 위치부터 위로 올라가기에, 동일한 이름의 변수가 지역, 전역에 모두 있는 경우 지역에 있는 변수가 사용된다
- 이 경우 전역에 있는 변수는 가려지게 되는데, 이를 변수 섀도잉이라고 한다 🐦
- 다만, 지역/전역에 같은 이름의 변수가 있더라도 전역의 변수를 참조할 수 있는 꼼수 방법은 있다 (전역 언섀도잉)
- window. 과 같이 전역 객체를 활용하여 전역 스코프의 변수를 직접 접근하는 방법이다. (비추천되긴 함. var나 function 변수만 가능)
- 원시값 복사가 아닌 객체 참조를 통해서 외부 프로퍼티에 직접 접근할 수 있다는 관점은 틀림.
- 참조 복사본을 통해 객체값을 수정하는 것은, 렉시컬 환경을 고려하여 변수 자체에 접근하는 것이 아님. (렉시컬 스코프는 그대로임)
- 섀도잉이 불가능한 조합도 있는데, let은 var를 가릴 수 있지만, var는 let을 가릴 수 없음 (구문 오류 발생)
- 함수 경계가 있는 경우에만 var는 let을 가릴 수 있다
- var 변수에 화살표 함수를 할당하는 경우에는, 함수 자체는 호이스팅 되지 않음
- 변수에 function 선언 함수를 할당하면, function 함수에 이름을 써줘도 읽기전용으로 선언되어 접근할 땐 변수 이름만 사용이 가능하다 (기명함수 표현식)
- 이 경우에 function 선언 함수의 이름을 써주지 않으면, 익명함수 표현식이 되고 스코프에 영향을 미치는 이름 식별자 자체가 없게 된다.
- ES6의 화살표 함수가 되입되었다. 이를 사용하면 function을 사용하지 않고 함수를 선언할 수 있다.
- 화살표 함수는 렉시컬 스코프 관점에서는 익명이다.
- 화살표 함수는 function 선언 함수와 동일하게 렉시컬 스코프의 규칙을 따름
- 화살표 함수는 익명이라는 특성을 빼면, function을 사용해 선언한 함수처럼 렉시컬 스코프 규칙을 받음.
/** * [1] 전역 스코프 * 이 파일 전체가 하나의 렉시컬 스코프 */ var globalVar = "global var"; let globalLet = "global let"; const globalObj = { count: 0 }; /** * [2] 함수 선언 * → 이 함수의 렉시컬 스코프는 "정의 시점"에 전역 스코프로 확정됨 */ function outer() { /** * [3] outer 함수 스코프 * 전역과는 분리된 새로운 스코프 */ var outerVar = "outer var"; let outerLet = "outer let"; // 전역 변수 접근 가능 (스코프 체인을 따라 위로 탐색) console.log(globalVar); console.log(globalLet); /** * [4] 블록 스코프 (let / const 전용) */ { let blockLet = "block let"; // blockLet은 여기서만 접근 가능 console.log(blockLet); // outer 스코프 변수 접근 가능 console.log(outerLet); // ❌ var는 블록 스코프를 만들지 않음 var leakedVar = "I am function scoped"; } // blockLet; // ReferenceError console.log(leakedVar); // 가능 (var는 함수 스코프) /** * [5] 변수 섀도잉 * 같은 이름의 변수가 더 안쪽 스코프에 존재 */ let shadow = "outer shadow"; function inner() { let shadow = "inner shadow"; // 가장 가까운 스코프의 shadow가 사용됨 console.log(shadow); // "inner shadow" // 전역까지 올라가며 탐색 가능 console.log(globalVar); } inner(); /** * [6] 전역 언섀도잉 (비추천) * var / function 으로 선언된 전역 변수만 가능 */ var globalVar = "outer globalVar shadow"; console.log(globalVar); // outer globalVar shadow console.log(window.globalVar); // 진짜 전역 globalVar /** * [7] 객체 참조와 스코프는 무관 */ function updateObject(obj) { // obj라는 식별자는 이 함수 스코프의 지역 변수 // 하지만 참조값을 통해 외부 객체의 프로퍼티를 수정할 수 있음 obj.count++; } updateObject(globalObj); console.log(globalObj.count); // 1 /** * [8] 기명 함수 표현식 */ const namedFn = function realName() { // realName은 함수 내부에서만 접근 가능 (읽기 전용) console.log("inside:", realName.name); }; namedFn(); // realName(); // ReferenceError /** * [9] 화살표 함수 * - 익명 함수 * - 렉시컬 스코프 규칙은 function과 동일 */ const arrowFn = () => { console.log("arrow:", outerLet); }; arrowFn(); } /** * [10] 함수 실행 * 호출 위치는 렉시컬 스코프에 영향 없음 */ outer(); /** * [11] var + 화살표 함수 호이스팅 차이 */ console.log(hoistedArrow); // undefined var hoistedArrow = () => { console.log("not hoisted as function"); };'JavaScript' 카테고리의 다른 글
Notes from reading 🔖 You Don't Know JS Yet - 10 (1) 2026.01.17 Notes from reading 🔖 You Don't Know JS Yet - 9 (0) 2026.01.03 Notes from reading 🔖 You Don't Know JS Yet - 7 (0) 2025.12.11 JavaScript AbortController 사용법 정리 (0) 2025.10.11 Symbol.for와 Symbol알아보기 (with. 활용 방법) (0) 2025.09.01