JavaScript ๊ณต๋ถํ๋ ์น๊ตฌ๊ฐ ๋ฌผ์ด๋ด์ ์๋ ค์ค ๊ฒธ ์ ๋ฆฌ
ย
(1)
์๋์ ๋ ์ฝ๋๋ ๋ธ๋ผ์ฐ์ (Chrome 91)์์ ์๋ก ๋ค๋ฅธ ์๋ฌ ๋ฉ์์ง๋ฅผ ๊ฐ๋๋ค
ย
console.log(foo); // ReferenceError: foo is not defined let foo;
{ console.log(foo); // ReferenceError: Cannot access 'foo' before initialization let foo; }
ย
์ด ๋์ด ์ด๋ค ์ฐจ์ด๋ฅผ ๊ฐ๊ณ ์๊ธฐ์ ์ด๋ฌํ ๊ฒฐ๊ณผ๊ฐ ๋์ค๋ ๊ฒ์ผ๊น?
์ด๋ฅผ ์์๋ณด๋๋ก ํ์
ย
ย
(2)
์ผ๋จ, Hoisting์ด Spec์๋ ์ด๋ป๊ฒ ๋ช
์๋์ด์๋์ง ๋ณด๋๋ก ํ๋ฉด...
ย
var
๊ฐ์ ๊ฒฝ์ฐ ์๋์ ๊ฐ๋ค[1]ย
Var variables are created when their containing Environment Record is instantiated and are initialized to undefined when created. A variable defined by a VariableDeclaration with an Initializer is assigned the value of its Initializer's AssignmentExpression when the VariableDeclaration is executed, not when the variable is created.
ย
var
ํค์๋๋ก ์ ์๋๋ ๋ณ์๋ ์์ ์ด ์ํ Environment Record[3]๊ฐ ์ด๊ธฐํ ๋ ๋ undefined
๊ฐ์ ๊ฐ๊ณ ์์ฑ๋๋ฉฐ, ์ดํ ์ค์ ๋ก ๊ฐ์ด ํ ๋น๋๋ ๊ตฌ๋ฌธ(AssignmentExpression[4])์ ๋ง์ฃผํ ๋ ๊ฐ์ด ๋ณ์์ ํ ๋น๋๋ค๋ ๋งย
์ด์๋ ๋ค๋ฅด๊ฒ
let
๊ณผ const
๋ ์๋์ ๊ฐ๋ค[2]ย
The variables are created when their containing Environment Record is instantiated but may not be accessed in any way until the variable's LexicalBinding is evaluated. A variable defined by a LexicalBinding with an Initializer is assigned the value of its Initializer's AssignmentExpression when the LexicalBinding is evaluated, not when the variable is created.
ย
let
๊ทธ๋ฆฌ๊ณ const
ํค์๋๋ก ์ ์๋๋ ๋ณ์ ์ญ์ ์์ ์ด ์ํ Environment Record๊ฐ ์ด๊ธฐํ ๋ ๋ ์์ฑ๋๋ ๊ฒ์ ๋์ผย
๋ค๋ง ์ค์ ๋ก ๋ฐ์ธ๋ฉ ๋๊ธฐ ์ ๊น์ง๋ ์ด๋ค ๋ฐฉ์์ผ๋ก๋ ์ ๊ทผ์ด ๋ถ๊ฐ๋ฅํ๋ฉฐ(TDZ, Temporal Dead Zone), ๋ฐ์ธ๋ฉ ์ดํ์๋ ์ด๊ธฐํ ๊ตฌ๋ฌธ์ด ์๋ ๊ฒฝ์ฐ ๊ฐ์ด ๋ณ์์ ํ ๋น๋๋ค๋ ์๋ฏธ์ด๋ค
ย
ย
(3)
๊ทธ๋ผ ๊ฐ๊ฐ์ Scope๋ ์ด๋ป๊ฒ ์ ์๋ ๊น?
์ด๊ฑด Spec๊ณผ Ecma TC39 ๋ฉค๋ฒ์ ๋ต๋ณ์ ํตํด ์์๋ณด์๋ฉด...
ย
๋จผ์
var
์ ๊ฒฝ์ฐ ๋ค์๊ณผ ๊ฐ๋ค[1]ย
A var statement declares variables that are scoped to the running execution context's VariableEnvironment.
ย
Running Execution Context์ VariableEnvironment๋ก Scope๊ฐ ์กํ๋ค๋ ๋ง
ย
let
๊ทธ๋ฆฌ๊ณ const
๋ ์ด๋ ๋ค[2]ย
let and const declarations define variables that are scoped to the running execution context's LexicalEnvironment.
ย
Running Execution Context์ LexicalEnvironment๋ก Scope๊ฐ ์กํ๋ค๊ณ ํ๋ค
ย
ย
(4)
VariableEnvironment์ LexicalEnvironment๋ ์ด๋ค ์ฐจ์ด๊ฐ ์๋ ๊ฒ์ผ๊น? ๊ทธ๋ฆฌ๊ณ ์ธ์ ์์ฑ(์ด๊ธฐํ)์ด ๋๋ ๊ฒ์ผ๊น?
ย
์ฐจ์ด๋ถํฐ ๋ณด์๋ฉด ์ด๋ ๋ค[5]
ย
A LexicalEnvironment is a local lexical scope, e.g., for let-defined variables. If you define a variable with let in a catch block, it is only visible within the catch block, and to implement that in the spec, we use a LexicalEnvironment. VariableEnvironment is the scope for things like var-defined variables. vars can be thought of as "hoisting" to the top of the function.
ย
๋น์ฐํ ๋ง์ด๊ธด ํ๋ฐ... ์ ๋ฆฌํ๋ฉด ์ด๋ ๋ค
ย
- LexicalEnvironment(Local lexical Scope) :
let
๊ณผ ๊ฐ์ ๋ณ์๊ฐ ์ ์ธ๋ ๋์ Scope
- VariableEnvironment :
var
๊ณผ ๊ฐ์ ๋ณ์๊ฐ ์ ์ธ๋ ๋์ Scope
ย
์์ฑ๋๋ ์์ ์ ์๋์ ๊ฐ๋ค
ย
To implement this in the spec, we give functions a new VariableEnvironment, but say that blocks inherit the enclosing VariableEnvironment.
ย
VariableEnvironment๋ ํจ์์ ํจ๊ป[5]
ย
{ StatementList }
1. Let oldEnv be the running execution context's LexicalEnvironment. 2. Let blockEnv be NewDeclarativeEnvironment(oldEnv). 3. Perform BlockDeclarationInstantiation(StatementList, blockEnv). 4. Set the running execution context's LexicalEnvironment to blockEnv. 5. Let blockValue be the result of evaluating StatementList. 6. Set the running execution context's LexicalEnvironment to oldEnv. 7. Return blockValue.
ย
LexicalEnvironment๋ Block ๊ตฌ๋ฌธ๊ณผ ํจ๊ป[6] ์์ฑ์ด ๋๋ค๋ ๊ฒ
ย
ย
(5)
์, ๊ทธ๋ผ ์ด์ ์ฒซ ๋ฒ์งธ ๊ฒฝ์ฐ์๋
ReferenceError: foo is not defined
๋ฅผ ์ค๋ช
ํด๋ณด๋๋ก ํ๊ฒ ๋คย
console.log(foo); // ReferenceError: foo is not defined let foo;
ย
์์์ ์ค๋ช
ํ๋ค์ถ์ด,
let
์ Environment Record๊ฐ ์ธ์คํด์คํ ๋ ๋ ๊ฐ์ด ์คํ๋๋ค๊ณ ํ๋ค. ๊ทธ๋ฐ๋ฐ ์ defined๊ฐ ๋์ง ์์๋ค๋ ๊ฒ์ผ๊น?ย
์ฌ์ค, ์๋ค์ถ์ด JavaScript๋ ์์์๋ถํฐ ํ ์ค ์ฉ ํ์ฑ ๋ฐ ์คํํด ๋๊ฐ๋ ์ธํฐํ๋ฆฌํฐ ์ธ์ด์ด๋ค
ย
๋ฐ๋ผ์ ์ฝ๋๋ ์ด๋ ๊ฒ ๋๋ ์ ์คํ๋๋ค
ย
console.log(foo);
let foo;
ย
์ฒซ ๋ฒ์งธ ์ฝ๋๋ฅผ ์คํํ๊ฒ ๋๋ฉด? ๋น์ฐํ
foo
๋ผ๋ ๋ณ์๊ฐ ์์ ์์ฑ์กฐ์ฐจ ๋์ด์์ง ์๊ธฐ ๋๋ฌธ์ ReferenceError: foo is not defined
๋ผ๋ ์๋ฌ๊ฐ ๋์ค๋ ๊ฒย
์ง๊ธ ๋น์ฅ ๊ฐ๋ฐ์ ๋๊ตฌ์ Console์ ์ด์ฉํด
console.log(notDefinedVariable)
๋ง์ ์
๋ ฅํด๋ณด๋ฉด ๋์ผํ ์๋ฌ๊ฐ ๋์ค๋ ๊ฒ์ ๋ณผ ์ ์๋คย
ย
(6)
์ด์ ๋ ๋ฒ์งธ ๊ฒฝ์ฐ
ย
{ console.log(foo); // ReferenceError: Cannot access 'foo' before initialization let foo; }
ย
์ฌ๊ธฐ์๋ Block Statement๊ฐ ๋์จ๋ค
ย
JavaScript์์๋ Block Statement๋ฅผ ๋ง์ฃผํ ๊ฒฝ์ฐ ์ด ์์ ๋ค์ด์๋ Variables, Constants, Functions, Classes์ ๋ํด Environment Record๋ฅผ ์๋ก ์์ฑํ๋ค[7]
ย
์ด ๊ณผ์ ์์, ์์ ๋งํ๋ฏ์ด
foo
๋ผ๋ ๋ณ์๊ฐ Environment Record์ ํจ๊ป ์์ฑ๋๊ฒ ๋๋ ๊ฒย
๋ฌผ๋ก '์ ๊ทผ์ ๋ถ๊ฐ๋ฅํ๊ธฐ์' ์์ ๊ฐ์ ์๋ฌ๊ฐ ๋ฐ์๋๋ ๊ฒ์ด๋ค
ย
์ด๊ฒ์ด ์ด ๋์ ์ฐจ์ด
ย
ย
(0)
References
ย
[1] https://tc39.es/ecma262/multipage/ecmascript-language-statements-and-declarations.html#sec-variable-statement
[2] https://tc39.es/ecma262/multipage/ecmascript-language-statements-and-declarations.html#sec-let-and-const-declarations
[3] https://tc39.es/ecma262/multipage/executable-code-and-execution-contexts.html#sec-environment-records
[4] https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#prod-AssignmentExpression
[5] https://github.com/tc39/ecma262/issues/736#issuecomment-261721158
[6] https://tc39.es/ecma262/multipage/ecmascript-language-statements-and-declarations.html#sec-block-runtime-semantics-evaluation
[7] https://tc39.es/ecma262/multipage/ecmascript-language-statements-and-declarations.html#sec-blockdeclarationinstantiation
ย