[JS ES6] Features

keymu·2025년 1월 3일
0

Scope란?

  • JavaScript에서 Scope는 변수가 유효한 범위를 의미
  • 코드의 어느 부분에서 변수에 접근하고 사용할 수 있는지를 결정하는 규칙

Scope의 종류

  • JavaScript에는 크게 3가지 종류의 Scope가 있습니다:

1. Global Scope (전역 범위)

  • 전역 범위에 선언된 변수는 코드 어디에서나 접근이 가능
let globalVar = "나는 전역 변수";
const globalConst = "나도 전역 변수";

function someFunction() {
    console.log(globalVar);     // "나는 전역 변수" 출력
    console.log(globalConst);   // "나도 전역 변수" 출력
}

someFunction();
console.log(globalVar);         // "나는 전역 변수" 출력

2. Function Scope (함수 범위)

  • 함수 내부에서 선언된 변수는 해당 함수 내에서만 접근이 가능
  • 특히 var 키워드로 선언된 변수는 함수 스코프를 가짐
function myFunction() {
    var functionVar = "함수 안에서만 살아요";
    console.log(functionVar);   // "함수 안에서만 살아요" 출력
}

myFunction();
// console.log(functionVar);    // 에러! functionVar는 함수 밖에서 접근 불가

3. Block Scope (블록 범위)

  • 중괄호 {} 내부에서 let이나 const로 선언된 변수는 해당 블록 내에서만 접근이 가능
if (true) {
    let blockVar = "블록 안에서만 살아요";
    const blockConst = "나도 블록 안에서만";
    console.log(blockVar);      // "블록 안에서만 살아요" 출력
    console.log(blockConst);    // "나도 블록 안에서만" 출력
}

// console.log(blockVar);       // 에러! 블록 밖이라 접근 불가
// console.log(blockConst);     // 에러! 블록 밖이라 접근 불가

변수 선언 방식에 따른 Scope 차이

var vs let/const

function scopeTest() {
    var functionScoped = "var는 함수 스코프";
    let blockScoped = "let은 블록 스코프";
    
    if (true) {
        var functionScoped2 = "여전히 함수 스코프";
        let blockScoped2 = "블록 스코프";
        console.log(functionScoped);   // 접근 가능
        console.log(blockScoped);      // 접근 가능
    }
    
    console.log(functionScoped2);      // 접근 가능
    // console.log(blockScoped2);      // 에러! 블록을 벗어남
}

키워드 없는 선언 (주의!)

function dangerousScope() {
    noKeyword = "위험해요!";  // 자동으로 전역 변수가 됨
}

dangerousScope();
console.log(noKeyword);  // "위험해요!" 출력 - 의도치 않은 전역 변수 생성

실제 사용 예시와 주의사항

// 블록 외부에서 선언
const outer1 = 100;
let outer2 = 200;
var outer3 = 300;

{
    // 블록 내부에서 외부 변수 접근
    console.log(outer1);  // 100
    console.log(outer2);  // 200
    console.log(outer3);  // 300
    
    // 블록 내부에서 새로운 변수 선언
    const inner1 = "블록 안";
    let inner2 = "블록 안";
    var inner3 = "함수가 아닌 블록에서 var는 전역이 됨";
}

// console.log(inner1);  // 에러! block scope
// console.log(inner2);  // 에러! block scope
console.log(inner3);     // "함수가 아닌 블록에서 var는 전역이 됨" - var의 특이한 동작

호이스팅이란?

  • JavaScript에서 변수나 함수의 선언이 코드의 최상단으로 끌어올려지는 것처럼 동작하는 현상

함수 호이스팅

  • 함수 선언문은 전체가 호이스팅
// 함수를 호출하고
hello();  // "안녕하세요!" 출력

// 나중에 함수를 선언해도 정상 작동합니다
function hello() {
    console.log("안녕하세요!");
}
  • 이것이 가능한 이유는 JavaScript 엔진이 코드를 실행하기 전에 함수 선언을 최상단으로 끌어올리기 때문

변수 호이스팅

  • var로 선언된 변수는 호이스팅되지만, 초기화는 호이스팅되지 않음
console.log(name);  // undefined
var name = "John";  

// 위 코드는 실제로 다음과 같이 동작
var name;          // 선언부가 위로 호이스팅됨
console.log(name); // undefined
name = "John";     // 할당은 원래 위치에서 실행

var vs let/const

// var의 경우
console.log(varVariable);  // undefined
var varVariable = 10;

// let의 경우
console.log(letVariable);  // ReferenceError!
let letVariable = 10;

// const의 경우
console.log(constVariable);  // ReferenceError!
const constVariable = 10;

호이스팅의 실제 예제

1. 함수 호이스팅

// 함수 호출이 선언보다 먼저 와도 동작
hello2();  // "hello2() 호출 실행되나요?" 출력

function hello2() {
    console.log("hello2() 호출 실행되나요?");
}

2. var 호이스팅의 특이한 동작

console.log(val_2);  // undefined
var val_2;          // 선언만 호이스팅됨

console.log(val_3);  // undefined
var val_3 = 10;     // 선언은 호이스팅되지만 할당은 그대로

val_4++;            // NaN - undefined에 증가 연산을 시도
console.log(val_4); // NaN
var val_4 = 10;

호이스팅이 문제가 되는 경우

1. 의도치 않은 undefined

function getName() {
    console.log(name);  // undefined
    var name = "John";  // 의도와 다르게 undefined 출력
    return name;
}

2. 변수 재선언으로 인한 혼란

var x = 1;
{
    console.log(x);  // undefined
    var x = 2;       // 호이스팅으로 인해 위의 x가 undefined
}

정리

  1. let과 const 사용하기
    • 호이스팅으로 인한 혼란을 방지
    • 더 예측 가능한 스코프 규칙
  2. 함수 선언을 코드 최상단에 배치
    • 호이스팅에 의존하지 않고 코드를 명확하게 작성
  3. 변수 선언과 초기화를 함께하기
    • 변수를 사용하기 전에 확실히 초기화
  • 호이스팅은 JavaScript의 독특한 특성 중 하나
  • ES6에서 도입된 letconst를 사용하면 호이스팅으로 인한 혼란을 크게 줄일 수 있음
  • 호이스팅을 이해하는 것은 JavaScript 코드의 동작을 예측하고 디버깅하는 데 매우 중요

++ 나중에 ESLint 라는 도구를 사용 시, hoisting 이 발생하는 곳에 경고 발생함


this 바인딩과 호출 방식 이해하기

  • 메서드 호출 방식에 따른 this 바인딩의 차이점

1. 일반적인 메서드 정의 방식들

const dog = {
    sound: "멍멍!",
    
    // 1. 이름 있는 함수
    say1: function aaa() {
        console.log(`say1: ${this.sound}`);
    },
    
    // 2. 익명 함수
    say2: function() {
        console.log(`say2: ${this.sound}`);
    },
    
    // 3. ES6 메서드 단축 구문
    say3() {
        console.log(`say3: ${this.sound}`);
    },
    
    // 4. 화살표 함수 (this 바인딩 주의!)
    say4: () => {
        console.log(`say4: ${this.sound}`); // undefined
    }
}

2. this 바인딩의 차이점

  • 메서드를 다른 변수에 할당할 때 this 바인딩이 어떻게 달라지는지 확인
const cat = {
    sound: "야옹~"
};

// 1. 메서드로 호출 - 정상 동작
cat.say1 = dog.say1;
cat.say1();  // "야옹~" 출력

// 2. 일반 변수에 할당 - this 바인딩 끊김
const 개냥이 = cat.say1;
개냥이();  // undefined

3. 해결 방법

  • this 바인딩이 끊기는 문제를 해결하는 여러 방법
// 1. bind() 사용
const 개냥이1 = cat.say1.bind(cat);

// 2. 화살표 함수로 감싸서 메서드 호출 형태 유지
const 개냥이2 = () => cat.say1();

// 3. call() 사용
const 개냥이3 = cat.say1;
개냥이3.call(cat);

정리

  • 메서드 호출 형태(객체.메서드())가 this 바인딩에 중요한 영향을 미친다.
  • 화살표 함수를 메서드로 직접 정의하면 this 바인딩이 일어나지 않는다.
  • 화살표 함수로 메서드를 감쌀 때는 내부에서 메서드 호출 형태를 유지하면 정상 동작한다.
profile
Junior Backend Developer

0개의 댓글