ARTICLE | [JS] JS 스코프

팀원들과 함께하는 모던 JS 딥다이브 스터디 4차 💕

이번 스터디부터는 의문점이나 궁금한 점에 대해 정리하기로 했다.
1. var키워드는 같은 스코프에서 중복 선언을 허용하지만,
let, const는 같은 스코프에서 중복 선언을 허용하지 않는다.
2. 동적스코프, 렉시컬스코프
3. 스코프체인

스코프

식별자가 유효한 범위

1. var키워드와 중복선언

스코프 내에서 식별자는 유일해야 하지만,
var 키워드로 선언한 변수는 중복 선언을 허용한다.

var x = '하이'
var x = '바이'

console.log(x) // '바이'
console.log(window.x) // '바이'
console.log(window.x === x) // true

전역에서'var' 키워드로 선언된 변수는 window 객체의 프로퍼티가 된다.

2. 동적 스코프 vs 렉시컬 스코프

함수가 상위 스코프를 결정할 때의 방법

  • 동적 스코프: 함수가 호출되는 시점에 동적으로 스코프를 결정
  • 렉시컬 스코프: 함수가 정의되는 시점에 정적으로 스코프를 결정 ✅
const x = 'global'

function foo() {
  const x = 'local'
    bar()
}

function bar() {
  console.log(x) // 'global'
}

foo();

JS는 렉시컬 스코프를 따른다.
때문에 bar 함수를 foo 함수 내부에서 호출하더라도
bar 함수의 상위 스코프는 전역 스코프이다.

3. Lexical nesting

⚠️ ES3에서는 스코프 탐색을 list 참조를 따라 찾아가는 방식이었지만,
ES5부터는 outer의 참조를 활용한다.
Lexical Environment
environmentRecordouter-Environment Reference(편의상 outer)를 포함하고 있다.
outer은 중첩 구조에서 상위에 있는 다른 Lexical Environment를 가르키기 때문에
outer를 통해 Lexical nesting이 형성된다.

// (1) 전역 컨텍스트
let a = 1;
function outer() {
  function inner() {
    let a = 3;
  }
  inner(); // (3) inner 함수 실행
}
outer(); // (2) outer 함수 실행

⚠️ 스코프는 함수 객체가 생성될 때 결정된다.
즉 (함수 선언문에 경우) 함수 정의가 평가될 때 스코프가 결정된다.
function 키워드를 만나면 함수 객체를 생성하고
함수 객체의 [[Scopes]]에 스코프를 설정한다.

함수가 호출되면 Lexical Environment의 outer의 스코프 참조에 설정된다.

함수 - 팀원 발표 간단 정리

contextual name

const hi = function () {}
console.log(hi.name)

이름이 없는 함수의 이름을 지정할 땐 컨텍스트에서 이름을 가져온다.

block 스코프와 렉시컬 환경

함수 몸체의 각 block은 고유한 lexical environment를 가진다.

느낀점

이 부분은 이미 다 알고 있다고 생각했지만 역시나 세상엔 완벽한 건 없나보다 ㅎㅎ
하나의 실행 컨텍스트에 한 개의 렉시컬 환경만 생성된다고 생각했었지만,
오늘 팀원분께서 함수 내에서 블록 스코프가 있을 땐 블록 스코프의 렉시컬 환경이 또 생성되고,
for 문과 같이 블록 레벨로 반복문이 있을 땐 반복되는 개수만큼의 렉시컬 환경이 생성된다는 걸 알았다.
하지만 함수 호출로 실행 컨텍스트가 스택에 쌓이는 것은 아니기 때문에 overflow가 발생하진 않는다고 얘기가 결론이 났는데 나중에 좀 더 찾아봐야겠다.

참고사이트)

스코프, 스코프체인, 클로저 | Alledy

실행컨텍스트와 스코프체인| bonobono

자바스크립트 실행 컨텍스 (Execution Context)

Lexical Environment, var 키워드 문제와 해결, 동적 환경

함수 name 프로퍼티

좋은 웹페이지 즐겨찾기