Chapter 2: Illustrating Lexical Scope - hochan222/Everything-in-JavaScript GitHub Wiki

μš©μ–΄ "lexical"λŠ” 컴파일의 첫 번째 단계 (μ–΄νœ˜ 뢄석/νŒŒμ‹±)을 μ˜λ―Έν•œλ‹€.

Marbles, and Buckets, and Bubbles... Oh My!

각 λ²”μœ„λŠ” μƒμœ„ λ²”μœ„μ— ν¬ν•¨λ˜λ©° 컴파일 쀑에 κ²°μ •λœλ‹€.

μ •ν™•νžˆλŠ” studentID λ§€κ°œλ³€μˆ˜λŠ” νŒŒλž€μƒ‰ λ²”μœ„μ— ν¬ν•¨λ˜μ§€ μ•ŠλŠ”λ‹€. (ν•˜μ§€λ§Œ μš°μ„  λ„˜μ–΄κ°€μž! 뒀에 λ‚˜μ˜΄)

id, name, log λŠ” λ³€μˆ˜κ°€ μ•„λ‹ˆκ³  속성이닀.

JS 엔진은 λ³€μˆ˜ 선언을 찾으면 μ†Œμ†λœ λ²”μœ„λ₯Ό μ§ˆμ˜ν•œλ‹€. λ³€μˆ˜/μ‹λ³„μžμ— λŒ€ν•œ μ°Έμ‘°λŠ” μƒμœ„ λ²”μœ„μ—μ„œλŠ” κ°€λŠ₯ν•˜μ§€λ§Œ ν•˜μœ„ λ²”μœ„μ—μ„œλŠ” λΆˆκ°€λŠ₯ν•˜λ‹€.
"shadows" scope에 μ†ν•˜μ§€ μ•ŠλŠ” ν•œ μœ„ λ²”μœ„ κ·œμΉ™μ„ λ”°λ₯Έλ‹€.

A Conversation Among Friends

  • Engine: JavaScript ν”„λ‘œκ·Έλž¨μ˜ μ‹œμž‘λΆ€ν„° λκΉŒμ§€ 컴파일 및 싀행을 λ‹΄λ‹Ήν•œλ‹€.
  • Compiler: Engine의 친ꡬ 쀑 ν•œ λͺ…μœΌλ‘œ νŒŒμ‹± ​​및 μ½”λ“œ μƒμ„±μ˜ λͺ¨λ“  λ”λŸ¬μš΄ μž‘μ—…μ„ μ²˜λ¦¬ν•œλ‹€.
  • Scope Manager: μ—”μ§„μ˜ 또 λ‹€λ₯Έ 친ꡬ둜 μ„ μ–Έ 된 λͺ¨λ“  λ³€μˆ˜/μ‹λ³„μžμ˜ 쑰회 λͺ©λ‘μ„ μˆ˜μ§‘ν•˜κ³  μœ μ§€ κ΄€λ¦¬ν•˜λ©° ν˜„μž¬ 싀행쀑인 μ½”λ“œμ— μ•‘μ„ΈμŠ€ ν•  μˆ˜μžˆλŠ” 방법에 λŒ€ν•œ 일련의 κ·œμΉ™μ„ μ μš©ν•œλ‹€.

μ•žμ—μ„œ λ³Έ λ‹€μŒ μ½”λ“œ

var students = [
  { id: 14, name: "Kyle" }, 
  { id: 73, name: "Suzy" }, 
  { id: 112, name: "Frank" }, 
  { id: 6, name: "Sarah" }
];

function getStudentName(studentID) { 
  for (let student of students) {
    if (student.id == studentID) { 
      return student.name;
    } 
  }
}

var nextStudent = getStudentName(73);

console.log(nextStudent);
// Suzy

μ—μ„œ 첫번째 λͺ…λ Ήλ¬ΈλΆ€ν„° 보면, μš°λ¦¬λŠ” ν•˜λ‚˜μ˜ μ„ μ–Έλ¬ΈμœΌλ‘œ λ³΄μ§€λ§Œ Engine은 두 개의 λ³„κ°œμ˜ μž‘μ—…μœΌλ‘œ μΈμ‹ν•œλ‹€. ν•˜λ‚˜λŠ” μ»΄νŒŒμΌλŸ¬κ°€ 컴파일 쀑에 μ²˜λ¦¬ν•˜κ³  λ‹€λ₯Έ ν•˜λ‚˜λŠ” 엔진이 μ‹€ν–‰ 쀑에 μ²˜λ¦¬ν•œλ‹€.

μ»΄νŒŒμΌλŸ¬λŠ” ν”„λ‘œκ·Έλž¨μ—μ„œ κ°€μž₯ λ¨Όμ € 렉싱을 μˆ˜ν–‰ν•˜μ—¬ ν† ν°μœΌλ‘œ λΆ„ν•  ν•œ λ‹€μŒ 트리(AST)둜 ꡬ문 λΆ„μ„ν•œλ‹€. μ»΄νŒŒμΌλŸ¬κ°€ μ½”λ“œλ₯Ό μƒμ„±ν•˜λ €λ©΄ 더 λ§Žμ€ κ³Όμ •μ΄μžˆλ‹€. λ‹€μŒμ€ μ»΄νŒŒμΌλŸ¬κ°€ 첫번째 ꡬ문을 μ²˜λ¦¬ν•˜λŠ” 단계이닀.

  1. var studentλ₯Ό λ§Œλ‚˜λ©΄ μ»΄νŒŒμΌλŸ¬λŠ” ν•΄λ‹Ή νŠΉμ • λ²”μœ„ 버킷에 λŒ€ν•΄ studentsλΌλŠ” λ³€μˆ˜κ°€ 이미 μ‘΄μž¬ν•˜λŠ”μ§€ ν™•μΈν•˜κΈ° μœ„ν•΄ λ²”μœ„ κ΄€λ¦¬μžμ—κ²Œ μš”μ²­ν•œλ‹€. 쑴재 ν•œλ‹€λ©΄ μ»΄νŒŒμΌλŸ¬λŠ” 이 선언을 λ¬΄μ‹œν•˜κ³  계속 μ§„ν–‰ν•œλ‹€. 그렇지 μ•ŠμœΌλ©΄ μ»΄νŒŒμΌλŸ¬λŠ” (μ‹€ν–‰μ‹œ) μŠ€μ½”ν”„ κ΄€λ¦¬μžμ—κ²Œ ν•΄λ‹Ή μŠ€μ½”ν”„ 버킷에 ν•™μƒμ΄λΌλŠ” μƒˆ λ³€μˆ˜λ₯Ό μƒμ„±ν•˜λ„λ‘ μš”μ²­ν•˜λŠ” μ½”λ“œλ₯Ό μƒμ„±ν•œλ‹€.
  2. 그런 λ‹€μŒ μ»΄νŒŒμΌλŸ¬λŠ” 엔진이 λ‚˜μ€‘μ— μ‹€ν–‰ν•  μ½”λ“œλ₯Ό μƒμ„±ν•˜μ—¬ student = [] 할당을 μ²˜λ¦¬ν•œλ‹€.

컴파일 κ³Όμ •μ—μ„œ __Scope Manager__와 __Compiler__λŠ” λŠμž„μ—†μ΄ μƒν˜Έ μž‘μš©ν•˜λ©΄μ„œ μ½”λ“œλ₯Ό μƒμ„±ν•œλ‹€.

Compiler : μ•ˆλ…•ν•˜μ„Έμš”, Scope Manager (Global), studentsμ΄λΌλŠ” μ‹λ³„μžμ— λŒ€ν•œ 곡식 선언을 μ°Ύμ•˜μŠ΅λ‹ˆλ‹€. λ“€μ–΄ λ³Έ 적이 μžˆμŠ΅λ‹ˆκΉŒ?
(Global) Scope Manager : μ•„λ‹ˆμš”, λ“€μ–΄ λ³Έ 적이 μ—†μ–΄μ„œ 방금 λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.
Compiler : μ•ˆλ…•ν•˜μ„Έμš”, Scope Manager, getStudent-Nameμ΄λΌλŠ” μ‹λ³„μžμ— λŒ€ν•œ 곡식 선언을 μ°Ύμ•˜μŠ΅λ‹ˆλ‹€. λ“€μ–΄ λ³Έ 적이 μžˆμŠ΅λ‹ˆκΉŒ?
(Global) Scope Manager : μ•„λ‹ˆμš”,ν•˜μ§€λ§Œ 방금 λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.
Compiler : Hey, ))Scope Manager__, getStudentName이 ν•¨μˆ˜λ₯Ό 가리 ν‚€λ―€λ‘œ μƒˆ λ²”μœ„ 버킷이 ν•„μš”ν•©λ‹ˆλ‹€.
(Function) Scope Manager : μ•Œκ² μŠ΅λ‹ˆλ‹€. μ—¬κΈ° λ²”μœ„ 버킷이 μžˆμŠ΅λ‹ˆλ‹€.
Compiler : μ•ˆλ…•ν•˜μ„Έμš”, Scope Manager (Function), studen-tID에 λŒ€ν•œ 곡식 맀개 λ³€μˆ˜ 선언을 μ°Ύμ•˜μŠ΅λ‹ˆλ‹€. λ“€μ–΄ λ³Έ 적이 μžˆμŠ΅λ‹ˆκΉŒ?
...

그리고 λŸ°νƒ€μž„ κ³Όμ •μ—μ„œλŠ” __Scope Manager__와 __Engine__이 λŒ€ν™”ν•œλ‹€.

(Global) Scope Manager : λ„€, μ—¬κΈ° λ³€μˆ˜κ°€ μžˆμŠ΅λ‹ˆλ‹€.
Engine : Scope Manager, λͺ©ν‘œλ¬Όμ„ μ°Ύμ•˜μŠ΅λ‹ˆλ‹€. students μ°Έμ‘°λ₯Ό μ°Ύμ•˜μŠ΅λ‹ˆλ‹€, λ“€μ–΄ λ³Έ 적이 μžˆμŠ΅λ‹ˆκΉŒ?
(Global) Scope Manager : 예, κ³΅μ‹μ μœΌλ‘œ 이 λ²”μœ„μ— λŒ€ν•΄ μ„ μ–Έλ˜μ—ˆμœΌλ―€λ‘œ 여기에 μžˆμŠ΅λ‹ˆλ‹€.
Engine : κ°μ‚¬ν•©λ‹ˆλ‹€. μ €λŠ” students듀을 μ΄ˆκΈ°ν™”ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. μ •μ˜λ˜μ–΄ μ‚¬μš©ν•  μ€€λΉ„κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€.
Engine : μ•ˆλ…•ν•˜μ„Έμš”, Scope Manager (Global), nextStudent의 λŒ€μƒ μ°Έμ‘°λ₯Ό μ°Ύμ•˜μŠ΅λ‹ˆλ‹€. λ“€μ–΄ λ³Έ 적이 μžˆμŠ΅λ‹ˆκΉŒ?
(Global) Scope Manager : 예,이 λ²”μœ„μ— λŒ€ν•΄ κ³΅μ‹μ μœΌλ‘œ μ„ μ–Έλ˜μ—ˆμœΌλ―€λ‘œ 여기에 μžˆμŠ΅λ‹ˆλ‹€.
Engine : κ°μ‚¬ν•©λ‹ˆλ‹€. nextStudentλ₯Ό undefined둜 μ΄ˆκΈ°ν™”ν•˜κ³  μžˆμœΌλ―€λ‘œ μ‚¬μš©ν•  μ€€λΉ„κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€.
...

λ”°λΌμ„œ, μš”μ•½ν•˜μžλ©΄ 첫 번째 λͺ…령문은

  1. μ»΄νŒŒμΌλŸ¬λŠ” λ²”μœ„ λ³€μˆ˜μ˜ 선언을 μ„€μ •ν•œλ‹€.
  2. Engine이 μ‹€ν–‰λ˜λŠ” λ™μ•ˆ λͺ…λ Ήλ¬Έμ˜ ν• λ‹Ή 뢀뢄을 μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄ Engine은 Scope Manager에 λ³€μˆ˜λ₯Ό μ‘°νšŒν•˜λ„λ‘ μš”μ²­ν•˜κ³  μ •μ˜λ˜μ§€ μ•Šμ€ μƒνƒœλ‘œ μ΄ˆκΈ°ν™”ν•˜μ—¬ μ€€λΉ„ν•˜μ—¬ λ°°μ—΄ 값을 ν• λ‹Ήν•œλ‹€.

Nested Scope

lexical scope의 μ£Όμš” μΈ‘λ©΄ 쀑 ν•˜λ‚˜λŠ” ν˜„μž¬ λ²”μœ„μ—μ„œ μ‹λ³„μž μ°Έμ‘°λ₯Ό 찾을 수 없을 λ•Œλ§ˆλ‹€ μ€‘μ²©μ˜ λ‹€μŒ μ™ΈλΆ€ λ²”μœ„λ₯Ό μ°Έμ‘°ν•œλ‹€λŠ” 것이닀. ν•΄λ‹Ή ν”„λ‘œμ„ΈμŠ€λŠ” 닡변을 μ°Ύκ±°λ‚˜ 더 이상 문의 ν•  λ²”μœ„κ°€ 없을 λ•ŒκΉŒμ§€ λ°˜λ³΅λœλ‹€.

Undefined Mess

선언이 μ•ˆλœ λ³€μˆ˜λŠ” "Reference Error: " μ—λŸ¬λ₯Ό 좜λ ₯ν•˜μ§€λ§Œ, μ„ μ–Έμ΄λ˜κ³  아무것도 할당이 μ•ˆλμ„ λ•ŒλŠ” "undefined" κ°€ 좜λ ₯λœλ‹€. 두 κ°œλ…μ„ ν˜Όλ™ν•˜μ§€ 말자.
ν•˜μ§€λ§Œ, typeof μ—°μ‚°μžλŠ” 두 μƒνƒœμ— λŒ€ν•΄ λͺ¨λ‘ undefinedλ₯Ό 좜λ ₯ν•œλ‹€.

var studentName;
typeof studentName; // "undefined"

typeof doesntExist; // "undefined"

이 λ•Œλ¬Έμ— μ„Έμ‹¬ν•˜κ²Œ 신경을 μ“°μž.

Global... What!?

λ³€μˆ˜κ°€ target이고 strict-modeκ°€ μ μš©λ˜μ§€ μ•ŠμœΌλ©΄ ν˜Όλž€μŠ€λŸ½κ³  λ†€λΌμš΄ λ ˆκ±°μ‹œ λ™μž‘μ΄ μ‹œμž‘λ©λ‹ˆλ‹€.
μ „μ—­ λ²”μœ„μ˜ λ²”μœ„ κ΄€λ¦¬μžκ°€ ν•΄λ‹Ή λŒ€μƒ 할당을 μˆ˜ν–‰ν•˜κΈ° μœ„ν•΄ μ‹€μˆ˜λ‘œ μ „μ—­ λ³€μˆ˜λ₯Ό μƒμ„±ν•œλ‹€.

function getStudentName() {
  // assignment to an undeclared variable :( 
  nextStudent = "Suzy";
}

getStudentName();
console.log(nextStudent);
// "Suzy" -- oops, an accidental-global variable!