본문 바로가기
CoreJavaScript-study/presentation

[발표1회차] 실행 컨텍스트(Execution Context)와 스코프

by 어느새벽 2024. 7. 5.

실행 컨텍스트란?

실행 컨텍스트란 프로그래밍에서 코드를 실행할 때 그 코드를 이해하고 관리하는 일종의 환경이다. 예를 들면 수학문제를 푼다고 했을 때 책상에 앉아 연필, 종이 등이 사용하여 문제를 풀 것이다. 문제를 풀기 위해 준비환경 역할을 하는 책상처럼 코드가 실행될 때 필요한 정보나 상태를 담는 것을 실행 컨텍스트라고 한다.

 

실행 컨텍스트의 역할

변수관리 : 코드를 실행하는 동안 사용할 변수들을 저장하고 관리한다.

코드 실행 위치 관리 : 지금 코드의 어느 부분을 실행하고 있는지 추적한다.

함수 호출 관리 : 코드에서 호출할 때 함수의 실행 환경을 만들어준다. 

 

예시

function sayHello() {
    var name = "철수";
    console.log("안녕, " + name);
}

sayHello();

sayHello라는 함수가 호출되면 컴퓨터는 이 함수를 실행하기 위한 환경을 준비한다. 그 환경 안에는 name이라는 변수가 있고 그 값은 '철수'이다. 그리고 console.log를 통해 "안녕, 철수"라는 메시지를 출력한다. 이 모든 과정이 실행 컨텍스트라는 환경 안에서 이뤄진다.


VariableEnvironment란?

프로그래밍에서 '변수를 저장하고 관리하는 환경'을 뜻한다. 컴퓨터가 코드를 실행할 때 변수를 어디에 저장하고 어떻게 접근할지 결정하는 공간이다.

 

VariableEnvironment의 역할

변수 저장 : 변수를 선언하고 그 변수를 VariableEnvironment에 저장한다.

값 관리 : 변수에 값을 할당하거나 변경하면, 그 값도 VariableEnvironment에 저장된다.

변수 검색 : 변수를 사용할 때, VariableEnvironment에서 해당 변수를 찾아 그 값을 가져온다.

 

예시

function introduce() {
    var name = "영희";
    var age = 14;
    console.log("이름은 " + name + "이고, 나이는 " + age + "살이에요.");
}

introduce();

 

introduce 함수가 호출되면 name과 age라는 변수가 선언된다. 이 변수들은 VariableEnvironment에 저장되고 console.log 문장이 실행될 때, name과 age의 값을 VariableEnvironment에서 찾아 출력한다.

실행 컨텍스트는 코드를 실행하는데 필요한 환경을 뜻하는데, 그 중 변수 관리를 담당하는 부분이 바로 VariableEnvironment이다.

 

그리고 VariableEnvironment는 크게 두 가지 주요 부분으로 나뉜다.

Environment Record: 변수와 그 값을 저장하고 관리하는 공간.

Lexical Environment: 변수의 사용 범위와 스코프를 관리하는 환경, 그리고 Environment Record를 포함하고 있다.


Environment Record란?

Environment Record는 변수를 저장하고 관리하는 일종의 '장부'라고 생각하면 된다. 코드를 실행할 때 변수의 이름과 그 값이 기록되는 곳이다.

 

Environment Record의 역할

변수 저장 : 변수를 선언하면 그 이름과 값이 Environment Record에 기록된다.

값 관리 : 변수의 값이 변경되면 새로운 값이 같은 변수 이름으로 기록된다.

변수 검색 : 변수를 사용할 때 해당 변수가 Environment Record에 있는지 찾아보고, 있으면 그 값을 가져온다.

 

Environment Record 상세

  • Declarative Environment Records: 함수나 블록 스코프에서 변수와 함수 선언을 관리하는 데 사용된다.
  • Object Environment Records: 전역 객체(Global Object)와 같은 객체에서 변수와 함수 선언을 관리하는 데 사용된다.

예시

var x = 10;
var y = 20;

 

이 코드를 실행하면 x와 y라는 변수가 각각 10과 20의 값을 가지고 Environment Record에 기록된다. 나중에 x와 y를 사용하게 되면 Environment Record에서 해당 변수를 찾아 그 값을 사용한다.


Lexical Environment란?

Lexical Environment는 코드를 실행할 때 변수가 어디에서 유효한지, 즉 변수를 어디서 사용할 수 있는지를 정의하는 '환경'이다. 변수를 사용할 수 있는 '범위'를 결정하는 규칙을 담고 있는 공간이라고 생각하면 된다.

 

구성 요소

Environment Record: Lexical Environment 안에 실제 변수 이름과 값이 저장된 환경.

Outer Lexical Environment: Lexical Environment가 중첩된 경우, 외부의 Lexical Environment를 참조할 수 있는 포인터.

 

Lexical Environment의 역할

변수 스코프 관리 : 변수가 어디서 유효한지를 결정한다. 변수는 선언된 블록이나 함수 안에서만 사용 가능하다.

상위 스코프 접근 : 현재 Lexical Environment에 변수가 없을 때, 상위 Lexical Environment에서 변수를 찾는다.

 

Lexical Environment 상세

 

  • Function Lexical Environment: 함수가 호출될 때 만들어지는 환경.
  • Global Lexical Environment: 전역 코드가 실행될 때 만들어지는 환경.

예시

function outerFunction() {
    var outerVar = "밖에 있는 변수";

    function innerFunction() {
        var innerVar = "안에 있는 변수";
        console.log(outerVar); // "밖에 있는 변수" 출력
    }

    innerFunction();
}

 

outerFunction: outerVar는 outerFunction의 Lexical Environment에 기록된다.

innerFunction: innerVar는 innerFunction의 Lexical Environment에 기록되고, outerFunction의 Lexical Environment를 참조해서 outerVar를 사용할 수 있다.


ThisBinding이란?

함수가 호출될 때 this 키워드가 참조하는 객체를 결정하는 과정이다. 이 과정은 함수가 어떻게 호출되었는지에 따라 this가 가리키는 대상이 바뀌게 된다.

 

ThisBinding의 역할

컨텍스트 제어 : this가 가리키는 객체를 제어함으로써 객체의 속성과 메서드를 올바르게 참조하고 사용할 수 있다.

코드의 가독성 및 유지보수성 향상 : this를 이해하면 코드의 동작을 에측할 수 있고, 복잡한 코드에서 오류를 줄일 수 있다.

 

ThisBinding의 규칙

1. 전역 컨텍스트(Global Context)

전역 코드나 함수 내에서 this는 전역 객체를 가리킨다. 브라우저 환경에서는 window 객체, Node.js에서는 global 객체.

console.log(this); // 전역에서는 window 또는 global
function showGlobalThis() {
    console.log(this); // 전역 함수에서도 window 또는 global
}
showGlobalThis();

 

2. 함수 호출(Function Call)

단순히 함수를 호출하면 this는 전역 객체를 가리킨다.(엄격 모드에서는 undefined)

function showThis() {
    console.log(this); // 전역 객체 (window 또는 global) (엄격 모드에서는 undefined)
}
showThis();

 

3.메서드 호출(Method Call)

객체의 메서드를 호출하면, this는 메서드를 호출한 객체를 가리킨다.

var person = {
    name: "영희",
    greet: function() {
        console.log(this.name); // "영희"
    }
};
person.greet(); // 메서드 호출, this는 person 객체를 가리킴

 

4. 생성자 함수(Constructor Call)

new 키워드와 함께 함수를 호출하면, this는 새로 생성된 객체를 가리킨다.

function Person(name) {
    this.name = name;
}

var person1 = new Person("철수");
console.log(person1.name); // "철수"

 

5. 명시적 바인딩(Explicit Binding)

call, apply, bind 메서드를 사용하여 this를 명시적으로 설정할 수 있다.

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

var person2 = { name: "민수" };
greet.call(person2); // "민수", this가 person2로 설정됨

 

6. 화살표 함수(Arrow Function)

화살표 함수는 this를 상위 스코프의 this로 바인딩한다. 즉, 화살표 함수는 자신을 감싸는 함수나 코드 블록의 this를 그대로 사용한다.

var person3 = {
    name: "지수",
    greet: () => {
        console.log(this.name); // 전역 객체의 name을 참조하므로 undefined
    }
};
person3.greet();

 

7. 엄격 모드(Strict Mode)

엄격 모드에서는 함수 호출 시 this가 undefined로 설정된다.

"use strict";

function showStrictThis() {
    console.log(this); // undefined
}
showStrictThis();

호이스팅이란?

호이스팅이란 자바스크립트에서 변수와 함수의 선언이 코드의 최상단으로 끌어올려지는 현상이다. 이 때문에 변수가 선언도기 전에 사용할 수 있는 것처럼 보이게 된다. 예를 들어 책상을 정리한다고 했을 때 짐을 한쪽에 모아두었다가 나중에 다시 정리하는 것처럼 자바스크립트 엔진도 코드를 실행하기 전에 변수와 함수의 선언을 일단 코드의 최상단으로 끌어 올려서 처리한다.

 

호이스팅의 작동 방식

자바스크립트에서는 코드가 실행되기 전에 변수가 선언되었는지를 먼저 확인하고, 모든 변수와 함수의 선언을 코드의 맨 위로 끌어 올린다. 하지만 변수의 값 할당은 그대로 두기 때문에, 값 할당은 코드의 원래 위치에서 일어난다.

 

호이스팅의 주요 특징

  • 변수 선언 호이스팅 : 변수 선언이 코드의 최상단으로 끌어올려지지만, 값 할당은 원래 위치에 남아 있다.
  • 함수 선언 호이스팅 : 함수 선언도 코드의 최상단으로 끌어올려져서 함수가 호출되기 전에 미리 사용할 수 있다.

 

변수 선언 호이스팅 예시

console.log(a); // undefined
var a = 10;
console.log(a); // 10

 

var a 선언이 코드의 최상단으로 끌어올려져서 console.log(a)에서 오류 없이 undefined가 출력된다.

 

함수 선언 호이스팅 예시

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

function add(x, y) {
    return x + y;
}

 

위 코드는 함수 선언이 호이스팅되어, 함수가 정의되기 전에 호출이 가능하다.

 

호이스팅의 한계

호이스팅은 변수 선언과 함수 선언에만 적용되고, 변수의 값 할당이나 함수 표현식에는 적용되지 않는다.

 

함수 표현식 예시

console.log(multiply(2, 3)); // TypeError: multiply is not a function

var multiply = function(x, y) {
    return x * y;
};

 

위 코드에서 multiply는 함수 선언이 아니라 변수로 선언된 함수 표현식이기 때문에, 호이스팅이 되지 않아 오류가 발생한다.

 

호이스팅과 let, const

let과 const로 선언된 변수는 호이스팅되지만, var와 다르게 선언 전에는 사용할 수 없다. 이런 특징을 일시적 사각지대(TDZ, Temporal Dead Zone)라고 한다.

 

예시

console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 10;
console.log(b); // 10

 

let으로 선언된 변수 b는 호이스팅 되지만, 선언되기 전에는 사용할 수 없기 때문에 ReferenceError가 발생한다.


스코프란?

변수와 함수가 유효하게 작동하는 범위이다. 변수를 어디서 사용할 수 있는지를 결정하는 규칙을 말하는데 스코프는 크게 전역 스코프와 지역 스코프로 나뉜다. 

 

전역 스코프(Global Scope)

전역 스코프는 코드 어디서든 접근 가능한 범위이다.

var globalVar = "전역 변수";

function exampleFunction() {
    console.log(globalVar); // 전역 변수
}

exampleFunction();

 

지역 스코프(Local Scope)

지역 스코프는 함수나 블록 내에서만 접근 가능하다. 함수 내부에서 선언된 변수는 그 함수 내에서만 접근 가능하고, 외부에서는 접근할 수 없다.

function exampleFunction() {
    var localVar = "지역 변수";
    console.log(localVar); // 지역 변수
}

exampleFunction();
console.log(localVar); // 오류: localVar는 함수 외부에서 접근 불가

 

블록 스코프(Block Scope)

블록 스코프는 {}로 둘러싸인 블록 내에서만 접근 가능하다. let이나 const 키워드로 선언된 변수는 블록 스코프를 가지며, 블록 밖에서는 접근할 수 없다. 

if (true) {
    let blockVar = "블록 변수";
    console.log(blockVar); // 블록 변수
}

console.log(blockVar); // 오류: blockVar는 블록 외부에서 접근 불가

 

스코프 체인(Scope Chain)

스코프 체인은 변수의 값을 찾기 위해 스코프를 차례대로 탐색하는 구조를 말한다. 함수 내부에서 변수를 찾을 때, 현재 스코프에 변수가 없다면 외부 스코프를 차례로 탐색해 변수를 찾는다.

var globalVar = "전역 변수";

function outerFunction() {
    var outerVar = "외부 함수 변수";

    function innerFunction() {
        var innerVar = "내부 함수 변수";
        console.log(globalVar); // 전역 변수
        console.log(outerVar); // 외부 함수 변수
        console.log(innerVar); // 내부 함수 변수
    }

    innerFunction();
}

outerFunction();

 

스코프 체인은 innerFunction -> outerFunction -> 전역스코프 순으로 탐색한다.

 

outerEnvironmentReference

outerEnvironmentReference는 함수가 선언될 때, 그 함수가 속한 외부 환경을 참조하는 특성을 말한다. 이 참조를 통해 함수 내부에서 외부 스코프의 변수에 접근할 수 있다.

function outerFunction() {
    var outerVar = "외부 변수";

    function innerFunction() {
        console.log(outerVar); // outerVar를 외부 스코프에서 찾음
    }

    return innerFunction;
}

var inner = outerFunction();
inner(); // "외부 변수" 출력

 

outerFunction 내부에  innerFunction이 선언될 때, innerFunction은 outerFunction의 스코프를 참조할 수 있는  outerEnvironmentReference를 가지게 된다. 그래서 innerFunction이 호출될 때 외부 스코프의 outerVar에 접근할 수 있다.

 

 

'CoreJavaScript-study > presentation' 카테고리의 다른 글

[발표5회차] 클래스  (0) 2024.09.03
[발표4회차] 프로토타입  (0) 2024.07.24
[발표3회차] 클로저  (0) 2024.07.18
[발표2회차] this와 콜백함수  (0) 2024.07.08