공부

[ASAC] JavaScript : Hoisting ~ Async/Await

wjddnr0208 2025. 1. 5. 15:23

Hoisting (호이스팅)

JavaScript에서 변수와 함수 선언은 해당 스코프의 최상단으로 끌어올려지는 현상이 있다.

이를 호이스팅(Hoisting)이라고 한다. 함수와 변수의 선언 방식에 따라 동작이 다르다.

 

함수 선언문 (Function Declaration)

  • 호이스팅 발생 : 함수가 코드 실행 전에 메모리에 등록되므로 선언 전에 호출 가능.
hoisting() // 함수 호이스팅 = function is hoisted

function hoisting() {
	console.log('function is hoisted')
}

 

함수 표현식 (Function Expression)

  • 변수 호이스팅 발생 : 변수만 선언되고 초기화는 되지 않으므로 선언 전에 호출하면 오류 발생.
hoisting() // 변수 호이스팅 = ReferenceError: Cannot access 'hoisting' before initialization

let hoisting = function () {
	console.log('variable is hoisted')
}

함수와 메소드의 차이

  • 함수(Function) : 독립적으로 정의된 코드 블록으로 특정 작업을 수행하거나 값을 반환한다.
  • 메소드(Method) : 클래스나 객체 내부에 정의된 함수로 해당 객체의 속성에 접근하거나 객체와 관련된 작업을 수행한다.

주요 차이점

  • 독립성 : 함수는 독립적이지만, 메소드는 특정 객체에 속한다.
  • this사용 여부 : 메소드는 this 키워드를 사용해 객체의 속성에 접근할 수 있다.

클래스와 캡슐화

클래스는 캡슐화(encapsulation)를 통해 내부 필드를 숨기고 외부에는 최소한의 메소드만 공개한다.

클래스 내부에서 this는 해당 클래스의 필드를 가리킨다.

class Example {
    constructor(name) {
        this.name = name;
    }

    getName() {
        return this.name;
    }
}

화살표 함수

화살표 함수는 표현이 간결할 뿐만 아니라 this가 존재하지 않는다.
따라서 상위 스코프의 this를 그대로 사용한다.

특징

  • this, arguments, new.target이 없음
  • 동적 바인딩이 아닌 정적 바인딩(Lexical Scope)
  • 메소드로 사용 불가
const arrowFunc = () => {
    console.log("화살표 함수");
};


주의사항

  • 화살표 함수는 메소드로 사용할 수 없다. 클래스 내부에서 this에 접근하려면 일반 함수를 사용해야 한다.
class Example {
    name = "example";

    logName = () => {
        console.log(this.name); // 상위 스코프의 this
    };
}

변수 스코프와 바인딩

  • var : 함수 스코프. 글로벌 환경에 바인딩됨
  • let, const : 블록 스코프. 해당 블록 내에서만 접근 가능

일반 함수와 화살표 함수의 this

  • 일반 함수
    • 호출 컨텍스트에 따라 this가 달라짐
    • this는 메소드로 호출되면 객체를, 함수로 호출되면 전역 객체를 참조
  • 화살표 함수
    • this가 없으므로 상위 스코프의 this를 사용
const obj = {
    name: "example",
    regularFunc: function() {
        console.log(this.name); // example
    },
    arrowFunc: () => {
        console.log(this.name); // undefined (상위 스코프 참조)
    }
};

암시적 바인딩과 명시적 바인딩

  • 암시적 바인딩 : 객체 내부 메소드에서 this를 통해 객체 필드에 접근
  • 명시적 바인딩 : call, apply, bind를 사용해 this를 특정 객체로 설정
const obj = { name: "example" };

function logName() {
    console.log(this.name);
}

logName.call(obj); // 명시적 바인딩: example

객체 생성 방법

  • 함수와 new 키워드 사용
  • 클래스를 사용
  • JSON 리터럴로 생성
function User(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}

const user3 = new User("Name", "Test");
console.log(user3.firstName); // Name
console.log(user3.lastName); // Test
// 클래스 예시
class User {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}
// JSON 예시
{
	name: "TestName",
   	age : 10,
}

접근 제어자

JavaScript에서 클래스의 필드와 메소드는 기본적으로 공개(public)이다.

접근 제어자를 사용하면 정보 은닉이 가능하다.

  • Private 필드 : #을 필드명 앞에 추가
  • Private 메소드 : #을 메소드명 앞에 추가
class User {
    #firstName;
    #lastName;

    constructor(firstName, lastName) {
        this.#firstName = firstName;
        this.#lastName = lastName;
    }

    #getFullName() {
        return `${this.#firstName} ${this.#lastName}`;
    }

    printName() {
        console.log(this.#getFullName());
    }
}

ESM vs CJS

  • ESM (ECMAScript Module)
    • 필요할 때만 임포트 가능
    • 비동기 가능 (백엔드에서 사용)
  • CJS (CommonJS)
    • 모든 모듈을 한 번에 임포트
    • 비동기 불가 (프론트엔드에서 사용)
// ESM
import { moduleName } from "module";

// CJS
const moduleName = require("module");

Callback과 Promise

Callback

  • Callback : 함수의 파라미터로 전달되어 실행권을 이양받는 함수
  • 주로 비동기 함수에서 사용됨
function asyncFunc(callback) {
    setTimeout(() => {
        callback("비동기 완료");
    }, 1000);
}

asyncFunc(result => console.log(result));


특징

  • 콜백 지옥(Callback Hell)으로 코드 가독성이 떨어질 수 있음
  • 에러 처리가 복잡해질 수 있음

Promise

  • Promise는 Callback과 비동기 로직을 결합한 객체
  • 비동기 작업의 상태를 표현하며 3가지 상태로 나뉜다.
    • Pending : 수행 중
    • Fulfilled : 성공 (이행) = 연산이 성공적으로 완료된 상태
    • Rejected : 실패 (거부) = 연산이 실패한 상태

출처 : Asac 07 강의 자료

const promise = new Promise((resolve, reject) => {
    const success = true;
    if (success) resolve("성공");
    else reject("실패");
});

promise
    .then(result => console.log(result))
    .catch(error => console.error(error));

출처 : Asac 07 강의 자료


장점

  • 콜백 지옥을 해결하여 가독성이 향상
  • 체이닝을 통해 비동기 작업을 순차적으로 처리 가능

Async/Await

  • async 키워드는 함수를 Promise로 변환
  • await는 Promise가 해결될 때까지 기다림
  • 기존의 .then() 체이닝 방식보다 가독성이 높음
async function fetchData() {
    try {
        const result = await promise;
        console.log(result);
    } catch (error) {
        console.error(error);
    }
}

fetchData();

출처 : Asac 07 강의 자료


특징

  • 동기적인 코드 흐름처럼 보이지만 실제로는 비동기 작업을 처리
  • try-catch 블록으로 에러를 처리할 수 있음
  • 비동기 함수 내부의 return 값은 자동으로 Promise로 래핑됨