2차_2주차_이서연_회고록 - hyeone999/Docs-JS_deepDive_Study GitHub Wiki
23장 실행 컨텍스트
소스코드
소스 코드 | 내용 |
---|---|
전역 코드 | 전역에 존재하는 코드 |
함수 코드 | 함수 내부에 존재하는 코드 |
eval 코드 | eval 함수로 실행되는 코드 |
모듈 코드 | 모듈 내부에 존재하는 코드, 모듈 내부의 함수, 클래스 등의 내부 코드는 포함하지 않는다 |
평가
- 선언문 실행 → 스코프에 등록
실행
- 선언문 이외의 문 실행 -> 실행 컨텍스트
실행 컨텍스트
실행 컨텍스트 : 자바스크립트 엔진이 코드를 평가하고 실행하기 위한 환경
실행 과정
- 전역 코드 평가
- 전역 코드 실행
- 함수 코드 평가
- 함수 코드 실행
스택
const x = 1;
function foo() {
const y = 2;
function bar() {
const z = 3;
console.log(x + y + z);
}
bar();
}
foo(); // 6
실행 과정
- 전역 컨텍스트 생성
- foo 함수 호출
- bar 함수 호출
- bar 함수 종료
- foo 함수 종료
렉시컬 환경
: 상위 스코프에 대한 참조를 기록하는 자료구조로 실행 컨텍스트를 구성하는 컴포넌트
구성요소
- 환경 레코드 : 변수와 함수 선언 저장
- 외부 렉시컬 환경 참조 : 상위 스코프에 대한 참조를 유지하여 스코프 체인을 형성
실행 컨텍스트 생성과 식별자 검색 과정
- 전역 객체 생성
- 전역 코드 평가
- 전역 코드 실행
- foo 함수 코드 평가
- foo 함수 코드 실행
- bar 함수 코드 평가
- bar 함수 코드 실행
- bar 함수 코드 실행 종료
- foo 함수 코드 실행 종료
- 전역 코드 실행 종료
블록 레벨 스코프
- 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
- 함수 실행 컨텍스트 생성 → 함수 선언문 정의
- 함수 객체 내부에 전역 컨테스트의 렉시컬 환경(전역 스코프) 저장
- 전역 스코프를 상위 스코프로 기억
- 나중에 함수가 호출되었을 때 내부 슬롯 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 키워드는 함수 스코프를 따름 = 반복문 블록 안에 선언된 변수라고 하더라도 전체 함수 내에서 하나의 동일한 변수로 간주 → 모든 함수가 마지막 반복의 변수 값 하나만 기억하게 되는 현상이 발생
- 즉시 실행 함수 : 현재 반복 중인 값을 클로저로 감싸는 방식이 사용 = 매번 새로운 스코프를 만들어 주므로, 각 반복에서의 값을 기억
- let 키워드가 도입 : 블록 스코프를 따르기 때문에, 반복문이 실행될 때마다 매번 새로운 렉시컬 환경 생성 → 각 렉시컬 환경에는 고유한 변수 값이 들어가며, 클로저가 이 값을 제대로 기억
- 고차 함수 활용 : 반복문 없이도 각 요소에 대해 고유한 렉시컬 환경을 자동으로 생성 → 클로저의 실수 ↓
회고록 자바스크립트를 공부하면서 이 파트가 제일 어려웠던거 같다..솔직히 아직도 100% 이해되진 않았고 그래도 서로 발표하면서 정리하다 보니 조금은 알 거 같다. 앞으로 자바스크립트를 공부하는데 도움이 되도록 이 파트를 좀 더 깊게 공부할 필요가 있는 거 같다.