식별자 끌어올리기 <호이스팅>

정수현·2022년 10월 13일
1

호이스팅이란?

💡 호이스팅이란 코드드가 실행하기 전 변수선언/함수선언이 해당 스코프의 최상단으로 끌어 올려진 것 같은 현상을 말한다.

함수 호이스팅

함수 선언의 종류

함수 선언문

function add(x, y) {
	return x + y;
}
  • 변수에 할당할 수 없다.
  • 함수 이름을 생략할 수 없다.
  • 런타임 이전에 자바스크립트 엔진에 의해 함수 객체가 먼저 생성됨
  • 런타임에서 함수 선언문이 실행되기 이전에 함수를 참조할 수 있으며 호출할 수도 있다.
console.log(add(2, 5));

// 함수 선언문
function add(x, y) {
	return x + y;
}

함수 표현식

var sub = function(x, y){
	return x - y;
}
  • 변수에 할당할 수 있다.
  • 함수 이름을 생략할 수 있다.(익명함수)
  • 함수 표현식은 변수에 할당되는 값이 함수 리터럴인 문이다.
    • 함수 호이스팅이 발생하는 것이 아니라 변수 호이스팅이 발생.
  • 함수 표현식으로 정의한 함수는 반드시 함수 표현식 이후에 참조, 호출해야 한다.
console.log(sub(2, 5));

// 함수 표현식
var sub = function(x, y){
	return x - y;
}

함수 호이스팅이란?

💡 함수 선언문이 코드의 선두로 끌어올려진것 처럼 동작하는 **자바스크립트 고유의 특징**
  • 함수를 호출하기 전에 반드시 함수를 선언해야한다는 당연한 규칙을 무시

파이썬에서는 호이스팅이 일어나지 않는다.

c에서도 호이스팅이 일어나지 않아 앞에 선언을 다시 적어줘야 정상적으로 작동한다.


💡 JSON 창안한 더글라스 크락포트 왈

함수 선언문 대신 함수 표현식을 사용할 것을 권장

Javascript 의 변수 생성 단계

1. 선언 단계 (Declaration phase)

  • 변수를 실행 컨텍스트의 변수 객체에 등록하는 단계
  • 모든 선언문은 런타임 이전에 먼저 실행된다.
  • 자바스크립트 엔진은 코드를 실행하기 전 실행 컨텍스트를 위한 과정에서 모든 선언(var, let, const, function, class)을 스코프에 등록한다.

2. 초기화 단계 (Initialization phase)

let foo;
  • 실행 컨텍스트에 등록한 변수를 위한 메모리를 만드는 단계
  • 메모리가 만들어지면 처음에는 undefined 가 할당

3. 할당 단계 (Assignment phase)

foo = 123;
  • 사용자가 undefined 로 할당된 변수에 다른 값을 할당하는 단계



키워드 별 함수/변수 생성 단계

function (함수 선언문)

  • 선언, 초기화, 할당 단계가 동시에 이루어집니다.
  • 런타임 이전에 자바스크립트 엔진에 의해 함수 객체가 먼저 생성
function add(x, y) {
	return x + y;
}

console.log(add(2, 5));

var

  • 선언과 초기화 단계가 동시에 진행
  • 런타임 이전선언 단계와 초기화 단계가 실행
  • 할당 단계는 할당문에서 실행
  • 변수 선언문 이전에 변수를 참조할 수 있다.
console.log(foo_var);
var foo_var = 123;

let, const (+ class)

  • 선언, 초기화, 할당 단계가 각각 따로 이루어집니다.
  • 런타임 이전에는 선언 단계만 실행
  • 초기화 단계는 변수 선언문에 도달했을 때 실행
  • 초기화 단계가 실행되기 이전(일시적 사각지대에서)에 변수에 접근하려고 하면 참조 에러가 발생
    • 이 구간에서는 변수를 참조할 수 없다.
  • const 키워드로 선언한 경우, 선언과 초기화(초기화단계와 할당 단계)가 동시에 이루어져야 하지만 런타임 이전에는 실행될 수 없다.
  • let 예시
    console.log(foo_let);
    let foo_let = 123;
  • const 예시
    console.log(foo_const);
    const foo_const = 123;
  • 클래스(Class)도 동일하다.
    console.log(Tester);
    
    **class** Tester{
    	constructor(){
    		this.name = "test";
    	}
    }
💡 런타임 이전에 호출했을 때 어떤 결과가 나오는지를 생각하면 된다. 모든 식별자는 호이스팅된다. 모든 선언문은 런타임 이전에 먼저 실행되기 때문이다.

일시적 사각지대 (TDZ)

  • TDZ(Temporal Dead Zone)
  • 임시 접근 불가구역이라고도 함
  • 스코프의 시작점부터 초기화 단계(변수 선언문)전까지
  • 이 구간에 있는 변수를 참조하게 되면 에러가 발생한다.

그러면 let, const, class 는 호이스팅되지 않는가?

❌ 모든 식별자는 호이스팅된다. let, const, class도 호이스팅되지만, 호이스팅이 발생하지 않는 것처럼 동작할 뿐이다.

let, const

let foo = 1;

{
	console.log(foo);
	let foo = 2;
}

Uncaught ReferenceError: Cannot access 'foo' before initialization

  • let 키워드로 선언한 변수의 경우 호이스팅이 발생하지 않는다면 위 예제는 전역변수 foo의 값을 출력해야 한다. 하지만 let 키워드로 선언한 변수도 여전히 호이스팅이 발생하기 때문에 참조 에러가 발생한다.
  • 변수 선언문 이전에 일시적 사각지대에 빠진다.

class는?

const Person = ''
{
	// 호이스팅이 발생하지 않는다면 ''이 출력되어야 한다. 
	console.log(Person);
	class Person {}
}

Uncaught ReferenceError: Cannot access ‘Person’ before initialization.

  • 클래스 선언문으로 정의한 클래스는 함수 선언문과 같이 소스코드 평가 과정, 즉 런타임 이전에 먼저 평가되어 함수 객체를 생성한다. 이때 클래스가 평가되어 생성된 함수 객체는 생성자 함수로서 호출할 수 있는 함수, 즉 constructor이다. 생성자 함수로서 호출될 수 있는 함수는 함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성된다. 프로토타입과 생성자 함수는 단독으로 존재할 수 없고 언제나 쌍으로 존재하기 때문이다.
  • 클래스 선언문 이전에 일시적 사각지대에 빠지기 때문에 호이스팅이 발생하지 않는 것처럼 동작한다.

0개의 댓글