요약
지금까지는 전역 스코프에서 하위 스코프로 이어지는 중첩된 스코프에 대해 주로 알아봤음. => 스코프체인
그러나 변수가 어디 스코프에서 왔는지 아는 것은 아주 작은 부분일 뿐.
이번에는
스코프 안에서 문 이후에 변수 선언이 나온다면 어떻게 참조할까?
같은 스코프에 변수가 중복 선언된다면??
When Can I Use a Variable?
greeting();
// Hello!
function greeting() {
console.log("Hello!");
}
이 코드가 작동하는 이유는 뭘까?
변수 선언을 스코프의 시작 부분부터 볼 수 있는 게 호이스팅임.
함수선언은 호이스팅이 될 때, 값 참조까지 자동으로 초기화되기 때문에 위 코드가 작동하는 것.
let과 const도 호이스팅이 일어나지만, var과 함수선언과 달리 가까운 block에 연결됨. => 자세한 건 6장의 Scoping with Blocks에서...
Hoisting: Declaration vs. Expression
- 호이스팅은 함수표현식에는 안일어남.(함수 선언에만)
greeting();
// TypeError
var greeting = function greeting() {
console.log("Hello!");
};
이 경우 typeError가 나는 것에 주목해야 함.(래퍼런스 에러가 아니라)
greeting의 경우 자동으로 초기화가 진행되어 undefined값이 저장되고, 4행이 되어서야 값이 할당됨.
따라서 undefined 함수를 실행하려 해서 실패.
Variable Hoisting
greeting = "Hello!";
console.log(greeting);
// Hello!
var greeting = "Howdy!";
위 코드가 가능한이유는 호이스팅으로 undefined로 자동으로 초기화 됐기 때문.
Hoisting: Yet Another Metaphor
- 함수 선언이 먼저 호이스팅 되고, 변수 선언이 호이스팅 됨.
- 컴파일타임에 호이스팅 됨
Re-declaration?
var studentName = "Frank";
console.log(studentName);
// Frank
var studentName;
console.log(studentName); // ???
이 코드의 결과는 ??
"Frank"가 나옴.. 나도 undefined가 나올 줄 알았다.
왜냐하면 호이스팅 때문에 코드가 다음과 같이 작동함.
var studentName;
var studentName; // clearly a pointless no-op!
studentName = "Frank";
console.log(studentName);
// Frank
console.log(studentName);
// Frank
즉 var studentName; 이
var studentName = undefined;를 의미하는 것은 아님!!!!!!
- 그러나 let, const는 재정의 안됨.
Constants?
- const는 재할당 불가.
const studentName = "Frank";
console.log(studentName);
// Frank
studentName = "Suzy"; // TypeError
이 경우 SyntaxError가 아니라 TypeError가 나오는 것이 중요함.
Syntax에러는 실행되기 전에 구문오류이고,
TypeError는 실행 중에 발생하는 결함.
위 코드에서 재할당할 때 실패하는 것.
Loops
var keepGoing = true;
while (keepGoing) {
let value = Math.random();
if (value > 0.5) {
keepGoing = false;
}
}
let은 재선언이 안되지만, 위 코드에서 오류가 발생하지 않는다!!
=> 반복문을 돌 때마다 자체 스코프를 가지기 때문!!
=>그러나 const는 에러남... 상수이기 때문!
for (let i = 0; i < 3; i++) {
let value = i * 10;
console.log(`${ i }: ${ value }`);
}
이 코드는
{
// a fictional variable for illustration
let $$i = 0;
for ( /* nothing */; $$i < 3; $$i++) {
// here's our actual loop `i`!
let i = $$i;
let value = i * 10;
console.log(`${ i }: ${ value }`);
}
// 0: 0
// 1: 10
// 2: 20
}
다음처럼 나타낼 수 있다.
Uninitialized Variables (aka, TDZ)
- var과 마찬가지로 let도 호이스팅 됨. => 그러나 let은 undefined로 초기화되지 않음.
- TDZ는 변수가 존재하지만, 초기화되지 않은 상태로 존재하는 것.
- var도 기술적으로 TDZ를 가지고 있지만, 길이가 0일뿐임.
var studentName = "Kyle";
{
console.log(studentName);
// ???
// ..
let studentName = "Suzy";
console.log(studentName);
// Suzy
}
이 코드를 통해 let과 cosnt가 호이스팅 됨을 알 수 있다.
호이스팅이 되지 않는다면 studentName이 Kyle이 나와야 하지만,
호이스팅이 되고 초기화가 되지 않았기 때문에 에러가 남.
TDZ 오류를 피하는 최선의 방법은??? => let과 const를 최대한 블록 상단에 쓰는 것!
느낀 점
let, const 재선언 재할당, 호이스팅 같은 얘기는 이미 유명한 주제라 다 알고 있었지만 코드와 함께 더 정확히 이해할 수 있었다.
그러나 for문안에서 let i를 쓸 수 있었던 얘기는 좀 참신했다. 그동안 그냥 무의식적으로 사용해온듯하다.=> 각각의 블록 스코프가 만들어져서 사용 가능
그리고 var a;가 var a = undeinfed를 가리키지는 않는다는 것도 처음 알았다. let과 cosnt 사용에 익숙해져 이것이 당연하다고 느꼈던 모양이다.
'공부 정리 > You Don't Know Js' 카테고리의 다른 글
[YDKJ] Scope & Closures - Using Closures (0) | 2023.05.29 |
---|---|
[YDKJ] Scope & Closures - Limiting Scope Exposure (0) | 2023.05.27 |
[YDKJ] Scope & Closures - Around the Global Scope (0) | 2023.05.18 |
[YDKJ] Scope & Closures - The Scope Chain (1) | 2023.05.09 |
[YDKJ] Scope & Closures - Illustrating Lexical Scope (0) | 2023.05.08 |
댓글