[JavaScript] 자바스크립트 변수의 유효범위, 렉시컬 환경
글 작성자: 망고좋아
반응형
🎯 변수의 유효 범위, 렉시컬 환경
📝 렉시컬 환경
function printName() {
return 'Hyunsol'
}
function findName() {
return printName()
}
function sayMyName() {
return findName()
}
sayMyName()
- 렉시컬 환경이란 특정 코드가 작성, 선언된 환경(장소)을 의미한다.
- 총 4개의 실행 컨텍스트(1개의 글로벌 실행 컨텍스트와 3개의 개별적 실행 컨텍스트)가 생성된다.
- 각각의 실행 컨텍스트는 하나의 개별적인 소우주이다.
- 바꿔 말하면, sayMyName 함수, fineName 함수, printName 함수의 렉시컬 환경은 global이다.
- 만약 findName()이라는 함수 내에 let yourName = 'blahblah'라고 선언되어 있다면, 변수 yourName의 렉시컬 환경은 findName이다.
내가 사용하고자 하는 변수, 함수 등이 어떤 렉시컬 환경에 속해 있는지에 따라서 이용 가능한 변수가 달라진다.
즉, 어떤 변수나 함수의 값은 '어디에서 선언했는지', 즉 렉시컬 환경이 어디인지에 따라서 결정된다.
function printName() {
return 'Hyunsol'
}
function findName() {
return printName()
}
function sayMyName() {
return findName()
}
sayMyName()
- sayMyName 함수 내에서 findName 함수가 호출되기는 했으나 '어디에서 호출했는지'가 아니라 '어디에서 선언했는지'가 중요하다.
- findName 함수는 글로벌 실행 컨텍스트, 즉 global 함수 내에서 선언이 되어있다.
- findName 함수의 렉시컬 환경은 글로벌 실행 컨텍스트
- 글로벌 실행 컨텍스트 내에 존재하는 global이라는 객체 내의 property로 지정되어 있다.
- findName, printName, sayMyName 함수 모두 global 객체의 property 중 하나이다.
📝 단계 1. 변수
- 1. 환경 레코드
- 모든 지역 변수를 프로퍼티로 저장하고 있는 객체
- this 값과 같은 기타 정보도 여기에 저장된다.
- 2. 외부 렉시컬 환경에 대한 참조
- 외부 코드와 연관됨
'변수'는 특수 내부 객체인 환경 레코드의 프로퍼티일 뿐이다. 따라서 '변수를 가져오거나 변경'하는 것은 환경 레코드의 프로퍼티를 가져오거나 변경함을 의미한다.
- 위 코드는 렉시컬 환경이 하나만 존재한다.
- 변수를 가져오거나 변경하는 것은 환경 레코드의 프로퍼티를 가져오거나 변경함을 의미
- 전역 렉시컬 환경은 외부 참조를 갖지 않기 때문에 화살표가 null을 가리킨다.
📕 렉시컬 환경의 변화
- 1. 스크립트가 시작되면 선언한 변수 전체가 렉시컬 환경에 올라간다.
- 이때 변수의 상태는 특수 내부 상태(special internal state)인 'uninitialized’가 된다.
- 상태의 변수를 인지하긴 하지만, let을 만나기 전까진 이 변수를 참조할 수 없다.
- 2.
let phrase
값을 할당하기 전이기 때문에 프로퍼티 값은 undefined이다.- 변수를 사용할 수 있다.
- 3. 값 할당
- 4. 값 변경
📝 단계 2. 함수 선언문
- 함수 선언문(function declaration)으로 선언한 함수는 일반 변수와는 달리 바로 초기화된다는 점에서 차이가 있다.
- 함수 선언문으로 선언한 함수는 렉시컬 환경이 만들어지는 즉시 사용할 수 있다.
- 함수 표현식은 해당하지 않는다.
📝 단계 3. 부와 외부 렉시컬 환경
- 함수를 호출해 실행하면 새로운 렉시컬 환경이 자동으로 만들어진다.
say("John")을 호출하면 일어나는 내부 변화
- 호출 중인 함수를 위한 내부 렉시컬 환경과 내부 렉시컬 환경이 가리키는 외부 렉시컬 환경을 갖게 됩니다.
- 현재 실행 중인 함수인 →
say
- 전역 렉시컬 환경은 phrase와 함수 say를 프로퍼티로 갖는다.
- 현재 실행 중인 함수인 →
1. 코드에서 변수에 접근할 땐, 먼저 내부 렉시컬 환경을 검색 범위로 잡는다.
2. 내부 렉시컬 환경에서 원하는 변수를 찾지 못하면 검색 범위를 내부 렉시컬 환경이 참조하는 외부 렉시컬 환경으로 확장
3. 이 과정은 검색 범위가 전역 렉시컬 환경으로 확장될 때까지 반복
- 전역 렉시컬 환경에 도달할 때까지 변수를 찾지 못하면 엄격 모드에선 에러가 발생한다.
- 1. 함수
say
내부의alert
에서 변수name
에 접근 → 내부 렉시컬 환경을 살피기 → 내부 렉시컬 환경에서 변수name
을 찾음 - 2.
alert
에서 변수phrase
에 접근 →phrase
에 상응하는 프로퍼티가 내부 렉시컬 환경엔 없다. → 검색 범위는 외부 렉시컬 환경으로 확장 → 외부 렉시컬 환경에서phrase
를 찾음
📝 단계 4. 함수를 반환하는 함수
function makeCounter() {
let count = 0;
return function() {
return count++;
};
}
let counter = makeCounter();
📕 first
makeCounter()
가 실행되는 도중엔 본문(return count++)이 한 줄짜리인 중첩 함수가 만들어진다. 현재는 중첩 함수가 생성되기만 하고 실행은 되지 않은 상태이다.
모든 함수는 함수가 생성된 곳의 렉시컬 환경을 기억한다.
- 함수는 [[Environment]]라 불리는 숨김 프로퍼티를 갖는다.
- 여기에 함수가 만들어진 곳의 렉시컬 환경에 대한 참조가 저장된다.
📕 second
- 따라서
counter.[[Environment]]
엔{count: 0}
이 있는 렉시컬 환경에 대한 참조가 저장된다.makeCounter()
에서 선언되었으니까
- 호출 장소와 상관없이 함수가 자신이 태어난 곳을 기억할 수 있는 건 바로 이 [[Environment]] 프로퍼티 덕분이다.
- [[Environment]]는 함수가 생성될 때 딱 한 번 값이 세팅되고 영원히 변하지 않는다.
- counter()를 호출하면 각 호출마다 새로운 렉시컬 환경이 생성된다.
- 그리고 이 렉시컬 환경은 counter.[[Environment]]에 저장된 렉시컬 환경을 외부 렉시컬 환경으로서 참조한다.
📕 Third
function makeCounter() {
let count = 0;
return function() {
return count++;
};
}
let counter = makeCounter();
console.log(counter()) // ?
- 1. 자체 렉시컬 환경에서 변수를 찾기
- 2. 익명 중첩 함수엔 지역변수가 없기 때문에 이 렉시컬 환경은 비어있는 상황 →
<empty>
- 3. counter()의 렉시컬 환경이 참조하는 외부 렉시컬 환경에서
count
를 찾는다.- 변숫값 갱신은 변수가 저장된 렉시컬 환경에서 이뤄진다.
📌 참고
반응형
'프로그래밍 > JavaScript' 카테고리의 다른 글
[JavaScript] 자바스크립트 Promise (0) | 2021.11.17 |
---|---|
[JavaScript] 자바스크립트 History API (0) | 2021.11.16 |
[JavaScript] 자바스크립트 블록레벨 스코프, 함수레벨 스코프 (0) | 2021.11.15 |
[JavaScript] 자바스크립트 var, let, const 차이점, 호이스팅(Hoisting), for문 안에 setTimeout을 사용할 때 var와 let의 차이점 (0) | 2021.11.15 |
[JavaScript] 자바스크립트 전개 연산자란? (0) | 2021.11.13 |
댓글
이 글 공유하기
다른 글
-
[JavaScript] 자바스크립트 Promise
[JavaScript] 자바스크립트 Promise
2021.11.17 -
[JavaScript] 자바스크립트 History API
[JavaScript] 자바스크립트 History API
2021.11.16 -
[JavaScript] 자바스크립트 블록레벨 스코프, 함수레벨 스코프
[JavaScript] 자바스크립트 블록레벨 스코프, 함수레벨 스코프
2021.11.15 -
[JavaScript] 자바스크립트 var, let, const 차이점, 호이스팅(Hoisting), for문 안에 setTimeout을 사용할 때 var와 let의 차이점
[JavaScript] 자바스크립트 var, let, const 차이점, 호이스팅(Hoisting), for문 안에 setTimeout을 사용할 때 var와 let의 차이점
2021.11.15