scope
scope는 식별자에 대한 유효범위이다.
Context vs Scope
The first important thing to clear up is that context and scope are not the same.
Every function invocation has both a scope and a context associated with it. Fundamentally, scope is function-based while context is object-based**. In other words, scope pertains to the variable access of a function when it is invoked and is unique to each invocation. Context is always the value of the this keyword which is a reference to the object that “owns” the currently executing code.
outerEnvironmentReference
식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해나가는 것. 그리고 이를 가능케 하는 것이 LexicalEnvironment
의 두번째 수집자료인 outerEnvironmentReference
이다.
outerEnvironmentReference
는 현재 호출된 함수가 선언될 당시의 LexicalEnvironment
를 참조한다.
선언하다라는 행위가 실제로 일어날 수 있는 시점이란 call stack상에서 어떤 실행 컨텍스트가 활성화된 상태일 뿐이다. 어떤 함수를 선언 혹은 정의하는 행위 자체도 하나의 코드에 지나지 않으며, 모든 코드는 실행 컨텍스트가 활성화 상태일 때 실행되기 때문이다.
outerEnvironmentReference
는 연결리스트 형태를 띈다. 선언 시점의 LexicalEnvironment
를 계속 찾아 올라가면 마지막엔 전역 컨텍스트가 있을 것이다. 가장 가까운 요소부터 차례대로만 접근할 수 있다.
그림으로 보면, 호출하는 함수 안으로 들어갈수록 점차 규모가 작아지는 반면 스코프 체인을 타고 접근 가능한 변수의 수는 늘어난다. 한 마디로, 가장 안에 있을수록 더 많은 변수에 접근할 수 있다.
variable shadowing : 이런 구조적 특성 덕분에 여러 스코프에서 같은 이름의 식별자를 선언한 경우엔 무조건 스코프 체인 상에서 가장 먼저 발견된 식별자에게만 접근 가능하다.
block scope
if else 블록은 scope를 따로 만들게 되지만, call stack에는 안 쌓인다. 해당 실행 컨텍스트의 call stack으로 유지됨.
try & catch의 경우 catch는 catch scope이 따로 있어서, error을 미리 인자값처럼 받고 시작한다.
scope chain
자바스크립트 엔진은 각각의 scope에 일종의 리스트 형태로 global execution context와 그 위에 쌓인 함수의 스코프의 레퍼런스를 순서대로 저장한다.스코프 체인은 식별자 중에서 객체(전역 객체 제외)의 프로퍼티가 아닌 식별자, 즉 변수를 검색하는 메커니즘이다.
javascript does this internally to search it in other Outer Environment
자바스크립트는 해당 변수를 찾을 때까지 바깥 environment에서 내부적으로 검색한다. 그리고 바깥 scope에서 내부 scope의 변수에는 접근할 수 없다.
엔진은 스코프 체인을 통해 렉시컬 스코프(Lexical Scope
)를 확인한다. 이렇게 순차적으로 리스트를 따라가며 검색하기 때문에 스코프 체인이라고 불린다. 마지막까지 검색에 실패하면 참조 에러가 발생한다.
예제 : 뭔가 이상한 변수 참조
const a = "Hello";
const bar = () => {
const c = "Hello c";
// (3)console.log(a)
console.log(b)
console.log(c)
};
const foo = ()=>{
bar()
const b = "Hello b";
// (2)console.log(a)
console.log(b)
console.log(c)
};
foo();
// (1)console.log(a)
console.log(b)
console.log(c)
지금 모든 함수에서 변수 a,b,c에 접근하고 있다. 그리고 javascript engine의 원칙에 의해서 이 코드에는 총 3개의 에러가 생긴다.
(1) global execution context
변수 a는 console.log함수를 통해 Hello로 잘 출력된다. 그러나 변수 b와 c의 경우엔 에러만 나온다.
Uncaught ReferenceError : b is not defined Uncaught ReferenceError : c is not defined
(2) foo함수의 execution context
변수 a와 b는 잘 출력된다. 그러나 변수 c는 에러와 함께 출력되지 않는다.
Uncaught ReferenceError : c is not defined
(3) bar 함수의 execution context
변수 a와 b와 c 모두 잘 출력된다.
전역 변수는 자제하자
코드의 안전성을 위해선 global variable의 사용을 최소화해야 한다. 최대한 각기 다른 실행 컨텍스트를 만들어서, 변수 호출이 겹치는 일이 없도록 해야 한다.
'language' 카테고리의 다른 글
제어자 (modifier) (0) | 2023.03.24 |
---|---|
OOP (0) | 2023.03.24 |
c언어. 구조체 (0) | 2022.12.21 |
c언어. 포인터와 주솟값 (0) | 2022.12.20 |
JS 실행 컨텍스트와 콜 스택 (0) | 2022.12.03 |