호이스팅과 TDZ는 무엇일까 ?

온두·2022년 7월 1일
0

스코프

전역 스코프 Global Scope : 전역 어느 곳에서든지 해당 변수에 접근할 수 있음
지역 스코프 Local Scope : 해당 지역에서만 접근 가능

자바스크립트에서 함수를 선언하면 함수를 선언할 때마다 새로운 스코프를 생성하게 됩니다. 그러므로 함수 몸체에 선언한 변수는 해당 함수 몸체 안에서만 접근할 수 있는데요. 이걸 함수 스코프(function-scoped)라고 합니다. 함수 스코프가 바로 지역 스코프의 예라고 할 수 있습니다.

var a = 1; // 전역 스코프
function print() { // 지역(함수) 스코프
 var a = 111;
 console.log(a);
}
print();
console.log(a);

호이스팅

함수 안에 있는 선언들을 모두 끌어 올려서 해당 함수 유효 스코프의 최상단에 선언 하는 것을 말합니다.

TDZ

선언 전에 변수를 사용하는 것을 비 허용하는 개념상의 공간입니다.

지역변수 : Block{}안에서 선언된 변수. Block 안에서만 쓸 수 있음.
전역변수 : Block{}밖에서 선언을 한 어디서든 쓰일 수 있는 변수

호이스팅 시 function 안에서 쓴 것 빼고는 전부 전역변수

let, const, var, function

  • var로 선언한 변수는 선언 전에 사용해도 에러x
    let, const는 에러 발생 o.

  • var는 이미 선언되어있는 이름과 같은 이름으로 변수를 또 선언해도 에러가 나지 않지만
    let, const는 이미 존재하는 변수와 같은 이름의 변수를 또 선언하면 에러가 납니다.

  • var, let은 변수 선언시 초기 값을 주지 않아도 되지만
    const는 반드시 초기값을 할당해야 합니다.

  • var, let은 값을 다시 할당할 수 있지만 const는 한번 할당한 값은 변경할 수 없습니다.

  • let, const의 경우 호이스팅이 되면서 초기 값이 없다면 var처럼 자동으로 초기값을 할당하지 않습니다.(const의 경우 선언시 초기값을 할당하지 않으면 문법 에러)
    그래서 값이 할당되기 전까지 메모리를 할당하지 않기 때문에
    선언전에(정확히는 값이 할당되기 전에) 사용하려고 하면 메모리에
    해당 변수가 존재하지 않아서 에러를 발생시킵니다.
    이처럼 변수가 선언되고 해당 변수에 값이 할당되기 전까지를
    TDZ(Temporal Dead Zone)라고 합니다.

함수 function?

하나의 특별한 목적의 작업을 수행하도록 설계된 독립적인 블록

필요할 때마다 호출하여 해당 작업을 반복해서 수행

function addNum(x, y) {

    return x + y;

}

document.write(addNum(2, 3));
  • 자바스크립트에서는 함수도 하나의 타입(datatype)

따라서 함수를 변수에 대입하거나, 함수에 프로퍼티를 지정하는 것도 가능

  • 자바스크립트 함수는 다른 함수 내에 중첩되어 정의될 수도 있습니다.

함수의 정의는 function 키워드로 시작되며, 다음과 같은 구성요소를 가집니다.

  1. 함수의 이름
  2. 괄호 안에 쉼표(,)로 구분되는 함수의 매개변수(parameter)
  3. 중괄호({})로 둘러싸인 자바스크립트 실행문

문법

function 함수이름(매개변수1, 매개변수2,...) {

    함수가 호출되었을 때 실행하고자 하는 실행문;

}

함수 이름(function name)은 함수를 구분하는 식별자(identifier)입니다.

매개변수(parameter)란 함수를 호출할 때 인수(argument)로 전달된 값을 함수 내부에서 사용할 수 있게 해주는 변수입니다.

예제

// addNum라는 이름의 함수를 정의함.

function addNum(x, y) {    // x, y는 이 함수의 매개변수임.

    document.write(x + y);

}

addNum(2, 3);              // addNum() 함수에 인수로 2와 3을 전달하여 호출함.

위의 예제에서 매개변수 x에는 인수 2가 저장되고, y에는 인수 3이 저장되어 사용됩니다.

이렇게 인수와 매개변수는 개수뿐만 아니라 순서 또한 매우 중요하게 적용됩니다.

함수의 인수(argument)란 함수가 호출될 때 함수로 값을 전달해주는 변수나 상수를 의미합니다.
반환(return)문
자바스크립트에서 함수는 반환(return)문을 포함할 수 있습니다.

이러한 반환문을 통해 호출자는 함수에서 실행된 결과를 전달받을 수 있습니다.

반환문은 함수의 실행을 중단하고, return 키워드 다음에 명시된 표현식의 값을 호출자에게 반환합니다.

반환문은 배열이나 객체를 포함한 모든 타입의 값을 반환할 수 있습니다.

예제

function multiNum(x, y) {

    return x * y;         // x와 y를 곱한 결과를 반환함.

}

var num = multiNum(3, 4); // multiNum() 함수가 호출된 후, 그 반환값이 변수 num에 저장됨.

document.write(num);

함수의 호출

정의된 함수는 프로그램 내에서 호출되어야 비로소 실행됩니다.

일반적인 함수의 호출은 함수의 정의문과 같은 형태로 호출할 수 있습니다.

함수의 정의

function addNum(x, y) {

    return x + y;

}

함수의 호출

var sum = addNum(3, 5); //함수 addNum()을 호출하면서, 인수로 3과 5를 전달합니다.

                        // 함수의 호출이 끝난 뒤에는 그 반환값을 변수 sum에 대입합니다.

위의 예제에서 인수(argument)로 전달된 숫자 3과 5는 함수에서 정의된 매개변수(parameter) x와 y에 각각 대입됩니다.

따라서 호출된 함수의 내부에서는 매개변수 x와 y에 각각 3과 5가 대입되어 계산됩니다.

값으로서의 함수
자바스크립트에서 함수는 문법적 구문일뿐만 아니라 값(value)이기도 합니다.

따라서 함수가 변수에 대입될 수도 있으며, 다른 함수의 인수로 전달될 수도 있습니다.

함수를 변수에 저장하여 사용하는 예제

function sqr(x) {                // 제곱의 값을 구하는 함수 sqr를 정의함.

    return x * x;

}

var sqrNum = sqr;                // 변수 sqrNum에 함수 sqr을 대입함.

document.write(sqr(4) + "<br>"); // 함수 sqr을 호출함.

document.write(sqrNum(4));       // 변수 sqrNum를 함수처럼 호출함.

Execution Context 실행 컨텍스트

자바스크립트 코드가 실행되는 환경

  1. Global Execution context
    자바스크립트 엔진이 처음 코드를 실행할 때 Global Execution Context가 생성됩니다. 생성 과정에서 전역 객체인 Window Object (Node는 Global) 를 생성하고 this가 Window 객체를 가리키도록 합니다.

아무런 코드가 없더라도 자바스크립트 엔진은 파일을 실행시키는
시점에 아래와 같이 Global Execution Context 를 생성합니다.

  1. Function Execution context
    자바스크립트 엔진은 함수가 호출 될 때마다 호출 된 함수를 위한 Execution Context를 생성합니다. 모든 함수는 호출되는 시점에 자신만의 Execution Context를 가집니다.
  • 자바스크립트 엔진은 처음 코드를 실행할 떄 단 한번 Global Execution Context를 생성하며 함수를 호출할 때 마다 함수를 위한 Execution context를 생성합니다.

Call stack 콜 스택

코드가 실행되면서 생성되는 Execution Context를 저장하는 자료구조 입니다. 엔진이 처음 script를 실행할 때, Global Execution Context를 생성하고 이를 Call Stack에 push합니다. 그 후 엔진이 함수를 호출할 때 마다 함수를 위한 Execution Context를 생성하고 이를 Call Stack에 push 합니다.

자바스크립트 엔진은 Call Stack의 Top에 위치한 함수를 실행하며 함수가 종료되면 stack에서 제거(pop)하고 제어를 다음 Top에 위치한 함수로 이동합니다.

스코프 체인

스코프(scope)는 식별자에 대한 유효범위를 뜻합니다. 어떤 경계 A의 외부에서 선언한 변수는 A의 외부뿐 아니라 A의 내부에서도 접근이 가능합니다. 하지만 A의 내부에서 선언한 변수는 오직 A의 내부에서만 접근할 수 있습니다.

자바스크립트에서 스코프는 ES5까지는 오직 함수에 의해서만 스코프가 생성됐습니다. ES6에서는 블록에 의해서도 스코프가 생성이 됩니다. 하지만 이러한 블록에서 var로 선언한 변수에서는 스코프가 적용되지 않고 let, const, class, strict mode에서의 함수 선언 등에 대해서만 스코프로서의 역할을 수행합니다.

스코프 체인은 이러한 스코프(식별자의 유효 범위)를 안에서부터 바깥으로 차례차례 검색해 나가는 것을 말합니다. 이를 가능한 것은 LexicalEnvironment의 두 번째 수집 자료인 outerEnvironmentReference 때문입니다.

다음과 같이 A, B, C 함수를 차례차례 각 함수 내부에 선언한 경우, outerEnvironmentReference 는 상위 함수의 LexicalEnvironment를 참조합니다.

A 함수 선언 → (선언되는 순간) A 함수의 outerEnvironmentReference 는 전역 컨텍스트의 LexicalEnvironment를 참조합니다.
B 함수 선언 → (선언되는 순간) B 함수의 outerEnvironmentReference 는 A 함수의 LexicalEnvironment를 참조합니다.
C 함수 선언 → (선언되는 순간) C 함수의 outerEnvironmentReference 는 B 함수의 LexicalEnvironment를 참조합니다.
각 outerEnvironmentReference 는 오직 자신이 선언된 시점의 LexicalEnvironment만 참조하고 있으므로 가장 가까운 요소부터 차례대로만 접근할 수 있습니다. 이런 구조적 특성 덕분에 여러 스코프에서 동일한 식별자를 선언한 경우, 무조건 스코프 체인 상에서 가장 먼저 발견된 식별자에만 접근 가능합니다. 예제를 살펴보면,

var a = 1;
function outside() {
  function inside() {
    console.log(a);
    var a = 3;
  }
  inside();
  console.log(a);
}
outside();
console.log(a);

변수 은닉화

스코프 체인 상에 있는 변수라고 해서 무조건 접근 가능한 것은 아닙니다.
변수명 a는 전역, 그 아래 함수, 또 아래 함수에서도 등장합니다.
예를 들어 inside함수에서 변수명 a는 이미 선언되었기 때문에 식별자와 값을 찾은 것입니다.
(값은 할당된 것이 없었기 때문에 undefined를 출력이 됐습니다.)
즉, 이미 선언된 a의 값이 없다고 해서 상위 스코프의 a 값을 가져올 수 없습니다.

profile
똑쟁이 개발자

0개의 댓글