실행 컨텍스트&호이스팅&스코프

joseph·2024년 3월 22일
0

개념정리

목록 보기
15/16

소스코드 실행 과정

  1. 평가단계 :자바스크립트가 소스코드를 스캔해서 선언문과 같은 식별자를 환경 레코드(Environment Record)라는 객체에 기록해둔다.

    console.log(booung) // undefined
    
    var booung = 1
    var woowa = 2
    
    console.log(booung) // 1

  1. 실행단계 : 순차적으로 자바스크립트 코드를 실행하고 사용자가 할당한 값을 변수에 재할당한다.
  2. JS코드 실행에 대한 결과 도출

실행 컨텍스트

코드를 실행하는데 필요한 환경을 제공하는 객체

구조

  • Variable Environment → 식별자, 식별자에 바인딩 된 값, 상위 스코프에 대한 참조로 구성
    • Environment Record
    • Outer Lexical Environment Reference
  • Lexical Environment
    • Environment Record
    • Outer Lexical Environment Reference

Variable Environment와 Lexical Environment는 실행 컨텍스트가 처음 실행될 때 동일한 렉시컬 환경을 참조하지만 소스코드를 평가하는 과정에서 새로운 렉시컬 환경이 생성되고, 둘의 참조는 달라지게 된다.

Variable Envrionment

  • var키워드로 선언되는 변수, 함수가 저장
  • 외부 렉시컬 환경에 대한 참조 : Outer Environment(상위 스코프)

Lexical Environment

  • let const로 선언되는 변수
  • 외부 렉시컬 환경에 대한 참조 : Variable Environment

→ var로 선언되는 변수와 let/cont로 선언되는 변수의 스코프가 다르기 때문

  • This Binding
    • this 키워드가 바인딩되는 객체 → 호출되는 방식에 따라 결정
var a = 10

function outer(){
  var b = 20
  // console.log(a,b,c)
  function inner(){
    var c = 30
    console.log(a,b,c)
  }
  return inner()
}

outer() // 10, 20, 30


globalExecutionContext = {
  lexicalEnvironment:{
    environmentRecord: {
      a: 10,
      outer: <function>,
      global: <global Object>,
    },
    outerEnvrionmentReference: null, -> 상위 스코프를 참조
  },
}

outerExecutionContext = {
  lexicalEnvironment:{
    environmentRecord: {
      b: 20,
      inner: <function>,
    },
    outerEnvrionmentReference:
    globalExecutionContext.lexicalEnvironment
  },
}

innerExecutionContext = {
  lexicalEnvironment:{
    environmentRecord: {
      c: 30,
    },
    outerEnvrionmentReference:
    outerExecutionContext.lexicalEnvironment
  },
}

호이스팅

코드 실행 단계 전에 모든 소스 코드의 함수와 변수 선언을 스캔하고 그 변수를 선언하고 초기화하고 할당한다. 이를 호이스팅이라 한다.

자바스크립트 변수 생성 3단계

  1. 선언 : 변수를 실행 컨텍스트의 렉시컬 환경에 등록

  2. 초기화 : 등록된 변수를 위한 공간을 메모리에 확보. 이 단계에서 변수는 undefined로 초기화

  3. 할당 : undefined로 초기화된 변수에 실제 값을 재할당

  4. var

    console.log(a) // undefined
    var a = 10
    a   //10
    var a = 20
    a // 20
    • var는 선언과 동시에 undefined로 초기화 된다.
      선언되기 이전에 변수를 호출하면 레퍼런스 에러가 뜨는게 아니라 undefined가 뜨는 것. → 이후에 사용자가 변수에 값을 입력하면 재할당
  5. let/const

    • let/const는 선언되어도 undefined값으로 초기화되지 않고 선언만 메모리에 저장된다. 그래서 선언되기 전에 호출되면 레퍼런스 에러가 발생한다. → 일시적 사각지대
    • let 은 이후에 변수의 값을 재할당 할 수 있지만 const는 한번 할당한 값을 재 할당할 수 없다.

함수 표현식 vs 함수 선언문

JS에서는 함수를 변수에 담아 사용할 수 있는데, 이 경우에는 변수 호이스팅과 같은 방식으로 동작하고 이를 함수 표현식이라 한다

const a = () => {console.log('react')}
const b = function(){
  console.log('dev')
}
a()  // react
b()  // dev

그리고 변수에 담지 않고 함수를 선언하는 것을 함수 선언문이라 하는데, 이 경우에는 함수 선언과 동시에 f()함수가 생성이 된다. 그래서 함수 선언 이전에 함수가 호출에 되어도 레퍼런스 에러가 뜨지 않는다.

reactDev() //'react dev'

function reactDev(){
		console.log('react dev')
	}

스코프

식별자(변수)가 유효한 범위 → 변수 이름의 충돌을 방지

전역 스코프

어디서든지 참조 가능

지역 스코프

일정 스코프 내에서만 참조 가능

  • 함수 레벨 스코프(Function-level Scope)
    • 함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 외부에서는 참조할 수 없다. 즉, 함수 내부에서 선언한 변수는 지역 변수이다 →함수는 중첩이 가능하니 지역 스코프도 중첩이 가능
    • 함수의 중첩으로 인해 스코프가 계층적 구조를 가지게 되면 그것을 스코프 체인이라 부른다
  • 블록 레벨 스코프(Block-level Scope) →if, for, while, switch 등

모든 코드 블록 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조할 수 없다. 즉, 코드 블록 내부에서 선언한 변수는 지역 변수이다.

변수르 참조할 때 항상 하위 스코프에서 상위 스코프로 이동한다.

Lexical Scope

함수를 어디서 정의했는지에 따라 함수의 상위 스코프를 정적으로 결정

Dynamic Scope

함수를 어디서 호출했는지에 따라 함수의 상위 스코프를 결정

let은 블록스코프 내에서 재할당을 해도 바깥에서 선언한 것과는 다르게 동작한다. funciton스코프와도 마찬가지

  • 자바스크립트는 지역함수에서 전역함수로, 즉 하위 스코프에서 상위 스코프를 참조하게 된다. 하위 스코프에서 변수의 값을 찾지 못했을 때 상위 스코프로 올라가서 해당 변수의 값을 찾는다. 있으면 그 값을 반환하고 없으면 한단계 더 상위 스코프로 올라가서 해당 변수의 값을 찾는데, 전역 스코프에서도 그 값을 찾지 못하면 Refference error 에러가 발생한다

클로저

외부 함수보다 중첩 함수가 더 오래 유지되는 경우 이미 생명주기가 종료한 외부 함수의 변수를 참조할 수 있는 중첩 함수
상위스코프의 식별자를 찹조하고 있고, 본인의 외부 함수보다 더 오래 살아있다면 이를 클로저라 한다.
그리고 클로저에 의해 참조된 변수를 자유 변수라 한다

var outer = function(){
  var a= 1;
  var inner = function(){
    return ++a;
  };
  return inner
}

var playOuter = outer()

console.log(playOuter()) // 2
console.log(playOuter()) // 3
console.log(playOuter()) // 4

참조 카운트가 0이 되면 가비지 컬렉터의 수집 대상으로 없어짐 → 가비지컬렉터는 어떤 값을 참조하는 변수가 하나라도 있다면 수집 대상에 포함시키지 않는다.

자바스크립트 모든 함수는 상위 스코프를 기억한다. 그래서 이론적으로는 모든 함수가 클로저임


https://youtu.be/AlcRl4pJd0c?si=gLuUmX4QOb10XLpZ

https://youtu.be/8v-qFyJS8O8?si=x483VfruPrfsdUJq

https://youtu.be/KmpofpqkitA?si=LGmCml3LR2kIsOon

https://youtu.be/PVYjfrgZhtU?si=f6o2Dk0MkX_rzzXm

https://youtu.be/xJtVVLPxgco?si=cerFe0k79RCZbW-x

https://youtu.be/bwwaSwf7vkE?si=KICvwy-6GYR2K9Qz

https://youtu.be/QkCNba92Vqo?si=FyZU0bc615i-6iJd

https://velog.io/@cjkangme/JS-LexicalEnvironment-vs-VariableEnvironment

https://hanamon.kr/javascript-호이스팅이란-hoisting/

https://velog.io/@1nthek/JavaScript-변수와-함수-호이스팅Hoisting에-대해-알아보자

profile
내일도 모레도 글피도 엉금엉금

0개의 댓글