본문 바로가기
공부 정리/You Don't Know Js

[YDKJ] Scope & Closures - The (Not So) Secret Lifecycle of Variables

by 경적필패. 2023. 5. 22.
반응형

요약

 

지금까지는 전역 스코프에서 하위 스코프로 이어지는 중첩된 스코프에 대해 주로 알아봤음. => 스코프체인

그러나 변수가 어디 스코프에서 왔는지 아는 것은 아주 작은 부분일 뿐.

이번에는

스코프 안에서 문 이후에 변수 선언이 나온다면 어떻게 참조할까?

같은 스코프에 변수가 중복 선언된다면??

 

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 사용에 익숙해져 이것이 당연하다고 느꼈던 모양이다.

 

 

 

 

 

 

 

반응형

댓글