항해 99 2주차 Node.js 과제2

Seong Hyeon Kim·2022년 5월 18일
0

항해99

목록 보기
2/16
post-thumbnail

호이스팅

  • 호이스팅(Hoisting)의 개념
    함수 안에 있는 선언들을 모두 끌어올려진 않지만 실제로는 끌어올려진 것처럼 해당 함수 유효 범위의 최상단에 선언하는 것을 말한다.

[예시1]

function sum(a, b) {
  return a + b
}

var sumOneAndTwo = sum(1, 2)
// 출력값 :  3
  • 매우 간단하고 호이스팅을 테스트 해보기 좋은 코드다. 위의 코드는 언뜻 보기에도 아무 문제가 없이 실행될 것이고 a, b 값에 각각 1과 2가 전달되었으므로 3을 반환할 것이다. 예상 결과 값을 반환하며 sumOneAndTwo 변수에는 3이 담기게 된다.

  • 함수를 선언한 뒤에 함수를 실행하는 코드를 작성해서 함수를 호출하는 것이 일반적인데, 자바스크립트에서는 다른 방법으로 함수를 선언하고 호출할 수 있다.

[예시2]

var sumOneAndTwo = sum(1, 2)

function sum(a, b) {
  return a + b
}

// 출력값 : 3
  • 예시1과 마찬가지로 위의 코드 또한 정상적으로 동작한다. 함수 호출을 함수 선언보다 먼저했는데 함수가 정상적으로 호출이 된다. 타 언어에서는 이런 코드를 실행할 수 없다.

[java 예시1]

System.out.println(num);
int num = 1;

자바에서 java 예시1 같이 선언하면 에러가난다.

하지만 자바스크립트에서는 선언이 된 부분을 문서의 첫번째로 옮기기 때문에

[js예시1]

console.log(num);
var num =1;
이 코드를 실행하면 아래와 같이 동작한다는 것이다.

[js예시2]

var num;
console.log(num); 
var num = 1;

위의 두 코드들은 결과값이 모두 같게 나온다.

console.log 의 차이는 있어도 이미 이 코드들은 호이스팅이 되어있기 때문에 실제 결과값은 모두 동일하게 나오는것을 확인할 수 있다.


TDZ

  • TDZ : TDZ(Temporal Dead Zone) 란, 한글로 직역하자면 일시적인 사각지대란 뜻입니다. 이 일시적인 사각지대는 스코프의 시작 지점부터 초기화 시작 지점까지의 구간을 TDZ(Temporal Dead Zone) 라고합니다.

우선 TDZ를 알기전 미리 알아야될 부분을 미리 설명하겠습니다.

* 변수 선언의 3단계

TDZ는 아래의 내용으로 모든것을 설명할 수 있습니다.

javascript에서의 변수는 위의 사진처럼 선언, 초기화, 할당이라는 3가지 단계의 걸쳐서 생성됩니다.

  • 선언 단계(Declaration phase) : 변수를 실행 컨텍스트의 변수 객체에 등록하는 단계를 의미합니다. 이 변수 객체는 스코프가 참조하는 대상이 됩니다.

  • 초기화 단계(Initialization phase) : 실행 컨텍스트에 존재 하는 변수 객체에 선언 단계의 변수를 위한 메모리를 만드는 단계 입니다. 이 단계에서 할당된 메모리에는 undefined로 초기화 됩니다.

  • 할당 단계(Assignment phase) : 사용자가 undefined로 초기화된 메모리의 다른 값을 할당하는 단계 입니다.

지금까지 우리는 var 혹은 let/const를 그냥 사용하였지만 사실은 위 3가지 단계를 거쳐서 생성되는 것 이었습니다.그리고 var와 let/const의 차이는 이 3가지 단계의 순서에 차이가 존재합니다.

  • 위 사진은 var 키워드 변수의 라이프 사이클 입니다. var 키워드 변수는 변수 선언전에 선언 단계와 초기화 단계를 동시에 진행합니다.

  • 그래서 javascript는 실행 컨텍스트 변수 객체의 변수를 등록하고 메모리를 undefined로 만들어 버립니다.

  • 그렇기 때문에 변수를 선언하기 전에 호출을 해도 undefined로 호출이 되는 호이스팅이 발생하는 것 입니다.

그렇다면 let의 라이프 사이클을 한번 봐보도록 하겠습니다.

  • let으로 선언된 변수는 var 키워드와는 다르게 선언단계와 초기화 단계가 분리되어서 진행이 됩니다.

  • 그렇기 때문에 실행 컨텍스트에 변수를 등록했지만, 메모리가 할당이 되질 않아 접근할 수 없어 참조 에러(ReferenceError)가 발생하는 것 이고,이것을 보고 우리가 호이스팅이 되질 않는다!! 라고 오해할 수 밖에 없었던 것 입니다.

* TDZ는 스코프의 시작 지점부터 초기화 시작 지점까지의 구간을 말합니다.

즉, let 또한 선언전, 실행 컨텍스트 변수 객체에 등록이 되어 호이스팅이 되지만,

이 TDZ 구간에 의해 메모리가 할당이 되질 않아 참조 에러(ReferenceError) 발생하는 것 입니다.

  • 추가적으로 function 키워드 함수는 사진과 같이 변수선언 3단계를 동시에 진행해 버립니다.

실행 컨텍스트란?

실행 컨텍스트를 보기 앞서, Stack과 Queue에 대해 간략히 알아보겠습니다.

  • Stack, Queue
    Stack: LIFO (Last In First Out)
    Queue: FIFO (First In First Out)

  • Stack에서는 가장 마지막에 들어온 d,c,b,a 순으로 데이터를 꺼낼 수 있습니다.
    Queue에서는 제일 먼저 들어온 a,b,c,d 순으로 데이터를 꺼낼 수 있습니다.

실행 컨텍스트

  • 실행 컨텍스트란 실행할 코드에 제공할 환경 정보들을 모아 놓은 객체입니다.
    실행 컨택스트의 동작은, 동일한 환경에 있는 코드들을 실행할 때 필요한 환경정보를 모아 컨텍스트를 구성하고, 이를 콜 스택에 쌓아놓은 뒤, 가장 위에 있는 컨텍스트와 관련 있는 코드들을 실행하는 것으로 코드의 환경과 순서를 보장합니다.

하나의 실행 컨텍스트를 구성할 수 있는 방법으로는 다음과 같습니다

전역 공간
evel() 함수
함수
  • 흔히 실행 컨텍스트를 구성하는 방법은 함수를 실행하는 것입니다. 어떤 실행 컨텍스트가 활성화될 때 자바스크립트 엔진은 해당 컨텍스트에 관련된 코드들을 실행하는데 필요한 환경 정보들을 수집해서 실행 컨텍스트 객체에 저장합니다.
    [예시]
// ------------------- (1)
var a = 1;
function outer() {
  function inner() {
    console.log(a);
    var a = 3;
    // --------------- (2)
  }
  inner(); // -------- (3)
  console.log(a);
  // ----------------- (4)
}
outer(); // ---------- (5)
console.log(a);
// ------------------- (6)

실행 순서 : (1) → (5) → (3) → (2) → (4) → (6)

[참고사진]

실행 컨텍스트의 구조

  • 실행 컨텍스트 객체는 활성화되는 시점에 VariableEnvironment, LexicalEnviornment, ThisBinding 세 가지 정보 수집합니다.

1. VariableEnvironment

실행 컨텍스트를 생성할 때, VariableEnvironment에 정보를 먼저 담은 후 이를 그대로 복사해서 LexicalEnvironment를 만들고 이후에 LexicalEnvironment를 주로 활용하게 됩니다. 실행중에도 변경사항이 반영되지 않으며 초기 상태를 유지합니다.

내부 구성 요소 : 현재 컨텍스트 내의 식별자들에 대한 정보 + 외부 환경 정보가 선언 시점의 스냅샷으로 저장

  • environmentRecord (snapshot)
  • outerEnvironmentReference (snapshot)

2. LexicalEnvironment

내부 구성 요소 : VariableEnvironment와 동일하지만 변경 사항이 실시간으로 반영

  • environmentRecord
  • outerEnvironmentReference

* 함수선언문과 함수표현식의 차이

차이 1 : 문법

가장 당연하고 우선된 둘의 차이는 문법의 차이다.

  • 함수 선언식 : 함수 선언식은 일반적인 함수 선언을 말한다. 함수 선언식은 아래와 같은 문법으로 선언하고 호출할 수 있다.

  • 사실상 함수 선언문이라고 부르는 게 맞을 것이다. 하지만 함수 표현식과 비교를 하다보니 함수 선언문을 함수 선언식이라고도 부르는 것 같다.

/ 함수 선언문
function sayHi() {
    console.log('Hi!');
}

// 함수 호출
sayHi();

* 함수 표현식

  • 함수 표현식을 간단하게 요약하면 익명 함수를 값으로써 변수에 할당한 표현식을 함수 표현식이라고 한다. 함수 표현식은 아래와 같은 문법으로 선언하고 호출할 수 있다.
// 함수 선언문
let sayHello = function () {
    console.log('Hello!');
}

// 함수 호출
sayHello();

차이 2 : 스코프

두번째 차이는 스코프의 차이다.

  • 스코프(Scope)란?
    Scope. 자바스크립트에서 스코프는 우리말로 유효 범위라고 해석하는데, 유효 범위로 번역하는 글도 많이 있지만 그냥 한글 그대로로 스코프라는 용어를 상대적으로 더 많이 사용하는 것 같다.

  • 아무튼 말그대로 "어떤 값이 영향을 미칠 수 있는 범위" 를 스코프라고 말하며 크게는 전역 범위(Global Scope)와 지역범위(Local Scope) 두 가지로 나뉜다.

* 스코프에 따른 함수 범위

* var변수와 함수 선언문은 -> 함수 스코프(function scope)를 가진다.

* let과 const 변수 -> 블록 스코프(block scope)를 가진다. 

* 함수 선언문의 스코프

따라서, 함수 선언문은 함수 스코프를 가진다.

{
    function sayHi() {
      console.log('Hi!');
    }
}

sayHi();
  • 위 코드처럼 블록문 안에 함수를 선언해도 블록문 밖에서 아무렇지 않게 호출이 된다.
function myFunction() {
    function sayHello () {
      console.log('Hello!');
    }
    
    sayHello();
}

myFunction();
sayHello(); // 출력값 : Error
  • 하지만 위 코드처럼 함수 안에서 함수를 선언하고, 가장 바깥에서 sayHello 함수를 호출하면 Error가 발생한다.

* 함수 표현식의 스코프

함수 표현식은 어떤 키워드로 선언한 변수에 할당하는지에 따라 스코프가 달라진다.

{
    var sayHello = function () {
        console.log('Hello!');
    }
}

sayHello();
  • 위 코드 처럼 var변수에 함수를 할당할 경우에는 함수 스코프를 가진다.
{
  let sayHello = function () {
    console.log('Hello!');
  }
}

sayHello(); // Error
  • 반면에 let, const변수에 함수를 할당할 경우에는 블록 스코프를 가지게 된다.

차이 3 : 호이스팅

  • 함수 선언문과 함수 표현식의 세 번째 차이는 호이스팅이다.
함수 선언문은 호이스팅이 일어나고 
함수 표현식은 호이스팅이 일어나지 않는다.

다시 말하면 호이스팅은 '선언문'만 끌어올리기 때문에 함수 선언문과, 함수 표현식은 호이스팅의 차이가 있는 것이다.

* 함수 선언문의 호이스팅

sayHi();

function sayHi() {
  console.log('Hi!');
}
  • 위 코드는 콘솔에 Hi! 를 출력한다. 함수 선언문으로 작성된 sayHi함수의 선언문이 호이스팅되었기 때문이다.

* 함수 표현식의 호이스팅

sayHello(); // Error

let sayHello = function () {
  console.log('Hello!');
}
  • 함수 표현식의 경우에는 호이스팅이 일어나지 않기 때문에 이 경우 Uncaught ReferenceError: Cannot access 'sayHello' before initialization 라는 에러를 만나게 된다.

출처 : https://bigtop.tistory.com/40


profile
삽질도 100번 하면 요령이 생긴다. 부족한 건 경험으로 채우는 백엔드 개발자

0개의 댓글