2차_2주차_이서연_회고록 - hyeone999/Docs-JS_deepDive_Study GitHub Wiki

23장 실행 컨텍스트

소스코드

소스 코드 내용
전역 코드 전역에 존재하는 코드
함수 코드 함수 내부에 존재하는 코드
eval 코드 eval 함수로 실행되는 코드
모듈 코드 모듈 내부에 존재하는 코드, 모듈 내부의 함수, 클래스 등의 내부 코드는 포함하지 않는다

평가

  • 선언문 실행 → 스코프에 등록

실행

  • 선언문 이외의 문 실행 -> 실행 컨텍스트

실행 컨텍스트

실행 컨텍스트 : 자바스크립트 엔진이 코드를 평가하고 실행하기 위한 환경

실행 과정

  1. 전역 코드 평가
  2. 전역 코드 실행
  3. 함수 코드 평가
  4. 함수 코드 실행

스택

const x = 1;

function foo() {
  const y = 2;

  function bar() {
    const z = 3;
    console.log(x + y + z);
  }

  bar();
}

foo(); // 6

실행 과정

  1. 전역 컨텍스트 생성
  2. foo 함수 호출
  3. bar 함수 호출
  4. bar 함수 종료
  5. foo 함수 종료

렉시컬 환경

: 상위 스코프에 대한 참조를 기록하는 자료구조로 실행 컨텍스트를 구성하는 컴포넌트

구성요소

  • 환경 레코드 : 변수와 함수 선언 저장
  • 외부 렉시컬 환경 참조 : 상위 스코프에 대한 참조를 유지하여 스코프 체인을 형성

실행 컨텍스트 생성과 식별자 검색 과정

  1. 전역 객체 생성
  2. 전역 코드 평가
  3. 전역 코드 실행
  4. foo 함수 코드 평가
  5. foo 함수 코드 실행
  6. bar 함수 코드 평가
  7. bar 함수 코드 실행
  8. bar 함수 코드 실행 종료
  9. foo 함수 코드 실행 종료
  10. 전역 코드 실행 종료

블록 레벨 스코프

  • let, const 키워드로 선언한 변수는 모든 코드 블록을 지역 스코프로 인정하는 블록 레벨 스코프를 따름.
  • 코드 블록이 반복해서 실행될 때마다 코드 블록을 위한 새로운 렉시컬 환경을 생성

24장 클로저

클로저 : 함수가 선언된 렉시컬 환경과의 조합

const x = 1;

function outerFunc() { // 외부 함수
	const x = 10;

	function innerFunc() { // 중첩 함수
		console.log(x); // 10
	}

	innerFunc();
}

outerFunc();

→ outerFunc 함수 내부에 중첩 함수 innerFunc가 정의되고 호출되었으므로 외부 함수의 x변수에 접근 가능

const x = 1;

function outerFunc() {
	const x = 10;
    innerFunc();
}

function innerFunc() {
	console.log(x); // 1
}

outerFunc();

→ innerFunc가 중첩함수가 아니므로 outerFunc함수의 변수에 접근 불가

렉시컬 스코프

  • 함수의 호출위치가 아니라 정의 위치에 따라 상위 스코프를 결정 → 정적 스코프
  • 함수의 상위 스코프 결정 = 함수가 정의된 위치를 기준으로, 어떤 스코프를 참조
  • 함수를 어디서 호출하는지는 상위 스코프 결정에 어떠한 영향도 주지 못함.

함수 객체의 내부 슬롯

const x = 5;

function foo() {
    const x = 40;
    bar();
}

function bar() {
    console.log(x);
}

foo(); // 5
bar(); // 5
  1. 함수 실행 컨텍스트 생성 → 함수 선언문 정의
  2. 함수 객체 내부에 전역 컨테스트의 렉시컬 환경(전역 스코프) 저장
  3. 전역 스코프를 상위 스코프로 기억
  4. 나중에 함수가 호출되었을 때 내부 슬롯 Environmenrt 에 저장된 렉시컬 환경을 참조 = 함수가 만들어졌던 순간의 상위 스코프를 기억

클로저와 렉시컬 환경

  • outer 함수 종료 시 inner 함수 반환 → 함수 생명 주기 종료 = outer 함수의 실행 컨텍스트는 실행 컨텍스트 스택에서 제거. 그러나, outer 함수의 렉시컬 환경까지 소멸 x, inner 함수의 내부 슬롯에 참조
  • 상위 스코프의 어떤 식별자도 참조하지 않는 함수 클로저 x
  • 외부 함수보다 일찍 소멸되는 중첩 함수 클로저 x
  • 클로저는 상위 스코프의 식별자 중 클로저가 참조하고 있는 식별자나 기억

클로저의 활용

function makeCounter(aux) {
  // 카운터 상태 유지를 위한 자유 변수
  let counter = 0;
  //클로저 반환
  return function () {
    // 인수로 전달받은 보조 함수에 상태 변경 위임
    counter = aux(counter);
    return counter;
  };
}
// 보조함수
function increase(n) {
  return ++n;
}
function decrease(n) {
  return --n;
}
// makeCounter 함수를 호출해 함수를 반환할 때 반환된 함수는 자신만의 독립된 렉시컬 환경을 가짐
// 즉, increaser, decreaser 함수는 카운터 상태 연동 x
const increaser = makeCounter(increase);
console.log(increaser()); // 1
console.log(increaser()); // 2

const decreaser = makeCounter(decrease);
console.log(decrease()); // -1
console.log(decrease()); // -2

캡슐화 정보 은닉

  • 캡슐화 : 객체의 상태를 나타내는 프로퍼티와 동작을 나타내는 메서드를 하나로 묶는 것
  • 정보 은닉 : 외부에서 불필요하게 접근하지 못하도록 감추는 것
  • 자바스크립트는 public, private, protected 같은 접근 제한자를 제공하지 않음. → 객체의 모든 프로퍼티와 메서드는 기본적으로 외부에 공개
  • 단, 생성자 함수 안에만 존재하는 변수에는 접근 불가
인스턴트 메서드 프로토타입 메서드
객체가 생성될 때마다 중복 생성 중복 생성 방지 (즉시 실행 함수가 종료된 후 호출)
중복 생성 가능 단 한번 생성되는 클로저
자유변수를 통해 private 흉내 가능 x

자주 발생하는 실수

  • var 키워드는 함수 스코프를 따름 = 반복문 블록 안에 선언된 변수라고 하더라도 전체 함수 내에서 하나의 동일한 변수로 간주 → 모든 함수가 마지막 반복의 변수 값 하나만 기억하게 되는 현상이 발생
  1. 즉시 실행 함수 : 현재 반복 중인 값을 클로저로 감싸는 방식이 사용 = 매번 새로운 스코프를 만들어 주므로, 각 반복에서의 값을 기억
  2. let 키워드가 도입 : 블록 스코프를 따르기 때문에, 반복문이 실행될 때마다 매번 새로운 렉시컬 환경 생성 → 각 렉시컬 환경에는 고유한 변수 값이 들어가며, 클로저가 이 값을 제대로 기억
  3. 고차 함수 활용 : 반복문 없이도 각 요소에 대해 고유한 렉시컬 환경을 자동으로 생성 → 클로저의 실수 ↓

회고록 자바스크립트를 공부하면서 이 파트가 제일 어려웠던거 같다..솔직히 아직도 100% 이해되진 않았고 그래도 서로 발표하면서 정리하다 보니 조금은 알 거 같다. 앞으로 자바스크립트를 공부하는데 도움이 되도록 이 파트를 좀 더 깊게 공부할 필요가 있는 거 같다.