안녕하세요 YB 김고은입니다.
저번 시간에 this 와 bind에 대한 내용을 정리했었는데요!
이번에는 23장 실행컨텍스와, 13장 스코프, 호이스팅에 대해서 다뤄보기로해서 모던 자바스크립트 Deep Dive를 읽고
내용 정리 + 약간의 궁금증을 해결하는 식으로 아티클을 작성해보겠습니다.
실행컨텍스트
"실행 컨텍스트"는 소스코드를 실행하는 데 필요한 환경을 제공하고, 코드의 실행 결과를 실제로 관리하는 영역
다시말해, (1) 식별자를 등록하고 관리하는 스코프와 // (2) 실행 순서관리를 구현한 내부 매커니즘이다.
모든 코드는 실행 컨텍스트를 통해 실행되고 관리된다.
식별자와 스코프 => 실행 컨텍스트의 렉시컬 환경으로 관리
코드 실행 순서 => 실행 컨텍스트 스택으로 관리
요 두개를 어떻게 관리하는가를 뜯어서 설명
코드 실행 순서를 다루는 "실행 컨텍스트 스택 "
코드실행시 시간의 흐름에 따라 "실행 컨텍스트 스택"에 실행 컨텍스트가 push pop 되면서 순차적으로 동작함
const x = 10; // 전역변수
function foo () { //전역함수
const y = 2; // 지역변수
function bar (){ // 지역함수 (근데 이제 중첩된)
const z = 3; // 지역 변수
console.log(x+y+z); // 메서드
}
bar();
}
foo();
전역코드 평가와 실행
전역 코드 평가 start => 전역 실행 컨텍스트 생성 => 실행컨텍스트.push(전역 실행 컨텍스트) => 전역 함수 호출 (foo)
foo 함수 코드의 평가와 실행
전역코드 실행 중단 => 제어권 foo 내부로 넘어옴 => foo 실행 컨텍스트 생성 => 실행컨텍스트.push(foo 함수 실행 컨텍스트) => 중첩함수 호출 (bar)
bar 함수 코드의 평가와 실행
foo 함수 실행 중단 => 제어권 bar 내부로 넘어옴 => bar 실행 컨텍스트 생성 => 실행컨텍스트.push(bar 함수 실행 컨텍스트) => bar 함수 종료
=> 코드 제어권 foo 함수로 => bar 함수를 pop 해버림 => foo 함수 더 읽을거 없으면 종료
=> 코드 제어권 전역 함수로 => foo 함수를 pop 해버림 => 전역 함수 더 읽을거 없으면 종료 => 스택.length == 0
스코프와 식별자를 관리하는 렉시컬 환경
렉시컬 환경은 객체를 생성해서, 그 안에서 이제 식별자를 등록하고 관리
객체는 식별자를 키로 등록하고 , 이제 식별자에 바인딩된 값을 관리 (key : value = 식별자 : 바인딩된 값 ) 요꼴
렉시컬 환경은 두개의 컴포넌트로 구성
1) 환경 레코드 : 식별자 등록 + 바인딩된 값 관리 저장소
2) 외부 렉시컬 환경에 대한 참조 : 상위 스코프 (근데, 해당 실행 컨텍스트를 포함한 상위 코드의 렉시컬 환경 )
const x = 1;
function foo () {
const y = 2;
console.log(x + y );
}
이게 있다면 전역 렉시컬 환경 먼저
전역 렉시컬 환경의 환경 레코드 ==> {x: 1, foo: <function object>}
전역 렉시컬 환경의 스코프 체인 ==> 없지 (왜냐면 전역이 최상위 스코프니까)
foo 렉시컬 환경의 환경 레코드 ==> {y: 1}
foo 렉시컬 환경의 스코프 체인 ==> 전역 레시컬 환경
정리하자면, 실행 컨텍스트는 자바스크립트가 돌아가기 위한 실행되는 환경으로 식별자 관리 등록 + 흘러가는 코드 흐름 을 위한 것
이걸 위해서는 flow 동작을 위해 실행 컨텍스트 스택이 필요, 식별자와 그 바인딩된 값을 위해서 렉시컬 환경이 필요 + 근데 그 렉시컬 환경에서 외부 렉시컬 환경을 참조 하기도 함
실행 컨텍스트 생성 ➡️ 렉시컬 환경
(실행 컨텍스트 스택 안에 push 될거) (환경 레코드 + 외부 렉시컬 환경에 대한 참조)
(객체 환경 레코드 + 선언 환경 레코드)
이때 렉시컬 스코프는 함수를 어디에서 호출했는지가 아니라, 어디에 정의했는지에 따라서 상위 스코프를 결정
(렉시컬 스코프는 함수가 정의된 위치에 따라 그 함수가 접근할 수 있는 범위(주변에 어떤 코드가 있는지)를 정하는 규칙)
스코프 체인은 현재 실행중인 실행 컨텍스트에서 => 외부 렉시컬환경에 대한 참조로 이어지는 렉시컬 환경의 연속
식별자 검색할때는 항상 실행 컨텍스트의 렉시컬 환경에서 검색하기 시작!
스코프
스코프란 해석하면 유효범위로, 식별자(identifier)가 유효한 범위를 나타낸다!
모든 식별자(변수 이름, 함수 이름, 클래스 이름 등) 는 자신이 선언된 위치에 의해
다른 코드가 식별자 자신을 참조할 수 있는 유효 범위가 결정된다
어라라 스코프랑 생명주기랑 비슷한건가?
놉!
스코프(scope):
어디서 유효한지를 정함
어디에 선언 되었는지에 따라서 범위가 정해져서 해당 변수에 접근할 수 있는 범위가 정적으로 정의됨
js는 렉스컬 스코프 사용 / 스코프는 코드 작성시 결정 -> 실행에도 바뀌지 않음
생명주기(Lifecycle):
변수가 언제 생성되고 언제 소멸하는지를 관리
특정 스코프에 속한 변수라도, 메모리에 언제 생성되고 해제될지는 코드 실행 시점에 따라 동적으로 달리짐
식별자란 어떤 값을 구분하여 식별해낼 수 있는 고유한 이름인데, 스코프를 통해 식별자인 변수 이름 충돌을 방지하여 같은 이름의 변수를 사용할 수 있게 된 것!!
스코프 종류
스코프는 전역 / 지역으로 구분된다.
전역 변수는 어디서든지 참조 가능
지역변수는 지역 스코프와 하위 지역 스코프에서 유효
스코프체인
함수 몸체 내부에서 정의한 함수를 (container)=> 중첩함수(nested)
중첩 함수를 포함하는 함수를 (Wrapper) => 외부함수 (outer)
함수 중첩으로 인해 계층적 구조를 가지고 -> 체인으로 엮인듯한 스코프 체인 발생! (렉시컬 환경의 단방향 연결)
변수를 참조할때 js 엔진은 스코프 체인을 통해 변수를 참조하는 코드의 스코프에서 (start)
=> 상위 스코프 방향으로 이동하며 선언된 변수를 검색한다.
상위 스코프에서 유효한 변수 <---- 하위스코프에서 자유롭게 참조 가능 (like 전역변수 마구 쓸 수 있듯이)
근데 하위 스코프에서 유효한 변수 <---- 상위스코프에서 참조 불가 ❌
스코프 체인으로 연결된 스코프 계층 구조 == "부모 - 자식 관계의 상속"과 유사함
부모의 자산을 자식이 자유롭게 사용할 수 있지만, 부모는 자식의 자산을 사용할 수 없는 것처럼 스코프도 마찬가지!!
함수 레벨 스코프
코드 블록 단위가 아니라 함수에 의한 지역스코프를 인정하는 경우 ... var 키워드
(코드 블록 => if / while / try,catch )
var x = 1;
if (true) {
// var는 함수 단위 스코프만을 인정
// if 블록 내부에서 선언한 변수 x는 지역 스코프로 적용 ❌
// 따라서 x는 전역 변수인데, 이미 전역에 x 가 있으므로 중복선언되는 문제!! 값이 덮어써짐
var x = 10;
}
console.log(x); // 10
렉시컬 스코프
상위 스코프를 결정하는 두가지 패턴
1️⃣ 함수를 어디에서 호출했는지에 따라 함수의 상위 스코프를 결정
동적 스코프
2️⃣ 함수를 어디에서 정의했는지에 따라 함수의 상위 스코프를 결정
정적 스코프 (= 렉시컬 스코프 )
자바스크립트 + else => 렉시컬 스코프를 따른다
따라서, 함수를 어디에서 정의했는지에 따라 상위 스코프를 결정 (호출 위치는 상위 스코프에 어떠한 영향도 ❌)
그치만!! this 는 동적 스코프를 따른다는 점 🔮
https://wave-web.tistory.com/69
[Week 01] this 와 bind 를 알아보자
안녕하세요. YB 김고은입니다. js 스터디 1주차 아티클로 세미나 시간에 다루어보았던 js의 전반적인 내용 중일부를 선정하여 더 알아보기로 했었는데요! 저는 this 키워드와 bind 메소드에 대해서
wave-web.tistory.com
var x = 1;
function foo (){
var x = 10;
bar();
}
function bar () {
console.log(x); // 어디에서 호출을 하든 콘솔로그는 1
}
호이스팅
사실 요 내용은 아티클을 이미 작성했었다!
함수 호이스팅 / 변수 호이스팅
https://wave-web.tistory.com/44
호이스팅(hoisting) 에 관하여
안녕하세요. YB 김고은입니다오늘은 JS에서의 호이스팅에 대해서 다뤄보고자 합니다 변수나 함수의 선언 위치가 코드에 어떤 영향을 미치는지 알기 위해서 호이스팅을 공부하는건 필! 수! 라
wave-web.tistory.com
그치만 클래스 호이스팅은 없었기에 요기에 대해서 정리해보려고 한다
클래스 호이스팅
클래스 선언문은 소스 코드 평가과정 (런타임 이전)에서 함수 객체를 생성 -> 그것은 바로 constructor (생성자)
생성자 함수가 생기면, 이와 더불어 프로토타입도 같이 생성된다. (둘은 항상 쌍으로 존재)
그치만, 클래스는 클래스 정의 이전에 참조 불가!! (like const / let )
console.log(exClass) // ReferenceError: Cannot access 'exClass' before initialization
class exClass {}
호이스팅이 안되는건 아니고!! 호이스팅이 발생하나
let, const 와 같이 TDZ 에 놓이기 때문에 호이스팅이 발생하지 않는 것처럼 동작한다 .
var, let, const, function, class 키워드를 사용하여 선언된 모든 식별자는 호이스팅이 된다! (함수 표현식 제외)
왜냐하면 선언문은 런타임 이전에 먼저 실행되기 때문이다.
다만, TDZ에 놓이는 경우에는 값의 할당 이전에 접근할 수 없기 때문에 오류가 발생한다는 점 ! 알아두면 좋다
'자스핑' 카테고리의 다른 글
[Week02] 스코프, 호이스팅, 실행 컨텍스트 (1) | 2024.11.07 |
---|---|
[week 02] 실행 컨텍스트와 스코프, 호이스팅 (1) | 2024.11.07 |
[Week 01] 일급객체로 자스핑 시작 💛 (0) | 2024.10.30 |
[Week 01] Symbol.. 그는.. (0) | 2024.10.30 |
[week 01] javascript의 다양한 함수 선언 방식을 알아보자 (0) | 2024.10.30 |