let a = 2;
var c = "C"
function f() {
const a = "hi"
console.log(a); // hi
console.log(b); // B
}
Object.prototype.a = 1;
Object.prototype.b = "B"
f();
b는 선언한 적이 없는데 에러 없이 잘만 출력 된다. 어떻게 된 일일까.
실행 컨텍스트는 간단하게 아래 세 가지로 구성 되어 있다.
EC Stack = [global EC]
EC Stack Poped = []
"global EC"
{
outer : null
global EC.environment record {
f : Function
(함수는 바로 할당이 될 것 같다.. 그렇지 않아면 다음에 호출이 안될테니..)
c : undefined
object Environment Record : {
binding object : {
[[prototype]]
}
}
declarative Environment Record : {a : nothing}
}
}
EC Stack = [global EC, f() EC]
EC Stack Poped = []
"f() EC"
{
lexical environment : {
a : nothing
outer : variable environment
}
variable environment : {
outer : global EC.environment record {
f : Function
c : "C"
object Environment Record : {
binding object : {
[[prototype]]
}
}
declarative Environment Record : {a : 2}
}
}
}
EC Stack = [global EC, f() EC, console.log(a) EC]
EC Stack Poped = []
"console.log(a)" // "hi"
{
lexical environment : {
outer : {
f() EC.lexical environment : {
a : "hi"
outer : variable environment
}
}
}
variable environment : {
outer : global EC.environment record {
f : Function
c : "C"
object Environment Record : {
binding object : {
[[prototype]]
}
}
declarative Environment Record : {a : 2}
}
}
}
여기서 hi가 출력 되는걸 보니 lexical을 먼저 조회해서 있으면 갖다 쓰고
없으면 outer로 넘어가고 거기서 찾아서 없으면.. 이렇게 올라가는 것 같네요
lexical이 먼저 아닐까..
EC Stack = [global EC, f() EC, console.log(B) EC]
EC Stack Poped = [console.log(a) EC]
"console.log(b)" // b는 선언한 적이 없다!?
{
lexical environment : {
outer : {
outer : {
f() EC.lexical environment : {
a : "hi"
outer : variable environment
}
}
}
}
variable environment : {
outer : global EC.environment record {
f : Function
c : "C"
object Environment Record : {
binding object : {
[[prototype]]
}
}
declarative Environment Record : {a : 2}
}
}
}
lexical이나 variable에 없다
-> out 따라 간다.
-> 끝까지 가서 outer가 null이고, global environment
record의 binding object까지 간다
-> scope chain에는 없으므로 binding object(global object) 의 prototype에서 찾는다
이렇게 out을 타고타고 변수를 찾아 가는게 scope chain 입니다.
요기잉네?
window __proto__ 계속 펼치면 있습니다.
window는 최종적으로 object를 상속받기 때문에..
EC Stack = [global EC]
EC Stack Poped = [f() EC, console.log(B) EC]
"global EC"
{
outer : null
environment record : {
f : Function
c : "C"
object Environment Record : {
binding object : {
[[prototype]]
}
}
declarative Environment Record : {a : 2}
}
}
f가 실행되고 난 후의 global EC이다 a에는 2가 되어 있네요. f도 그대로 있고
c에는 "C"가 있습니다.
console.log(a)
let a = 10;
global EC에 declarative Environment Record의 a가 nothing이라 접근하면
Reference Error
console.log(a)
const a = 10;
global EC에 declarative Environment Record의 a가 nothing이라 접근하면
Reference Error
console.log(a)
var a = 10;
global EC에 environment record에 object Environment Record에 binding object에
a가 undefined이므로 undefined
test()
function test(){}
global EC에 environment record에 object Environment Record에 binding object에
test가 Function이므로 호이스팅!
test()
let test = function(){}
global EC에 declarative Environment Record의 test가 nothing이라 접근하면
test not defined
test()
const test = function (){}
global EC에 declarative Environment Record의 test가 nothing이라 접근하면
test not defined
test()
var test = function (){}
global EC에 environment record에 object Environment Record에 binding object에
test가 undefined라
test is not function
test()
let test = function test(){}
global EC에 declarative Environment Record의 test가 nothing이라 접근하면
test not defined
test()
const test = function test(){}
global EC에 declarative Environment Record의 test가 nothing이라 접근하면
test not defined
test()
var test = function test(){}
global EC에 environment record에 object Environment Record에 binding object
test가 undefined라
test is not function
function Test(){
var a = 0;
let b = 1;
const c = 2;
return function(){
console.log(a, b, c)
}
}
const t = Test();
t()
EC Stack = [global EC]
EC Stack Poped = []
"global EC"
{
outer : null
global EC.environment record {
Test : Function
object Environment Record : {
binding object : {
[[prototype]]
}
}
declarative Environment Record : {t : undefined}
}
}
EC Stack = [global EC]
EC Stack Poped = []
"Test() EC"
{
lexical environment : {
b : nothing
c : nothing
outer : variable environment
}
variable environment : {
a : undefined
outer : global EC.environment record {
Test : Function
object Environment Record : {
binding object : {
[[prototype]]
}
}
declarative Environment Record : {t : undefined}
}
}
}
EC Stack = [global EC]
EC Stack Poped = [Test() EC]
"global EC"
{
outer : null
global EC.environment record {
Test : Function
object Environment Record : {
binding object : {
[[prototype]]
}
}
declarative Environment Record : {t : Function(closure)}
}
}
EC Stack = [global EC, t() EC]
EC Stack Poped = []
"t() EC"
{
lexical environment : {
outer : variable environment
}
variable environment : {
a : 0
outer : Test() EC.lexical environment : {
b : 1
c : 2
outer : Test() EC.variable environment
}
}
}
EC Stack = [global EC, console.log(a, b, c) EC]
EC Stack Poped = [t() EC]
"console.log(a, b, c) EC" // 0, 1, 2
{
lexical environment : {
outer : t() EC. lexical environment : {
outer : Test() EC.variable environment
}
}
variable environment : {
a : 0
outer : Test() EC.lexical environment : {
b : 1
c : 2
outer : Test() EC.variable environment
}
}
}
EC Stack = [global EC]
EC Stack Poped = [console.log(a, b, c) EC]
"global EC"
{
outer : null
global EC.environment record {
Test : Function
object Environment Record : {
binding object : {
[[prototype]]
}
}
declarative Environment Record : {t : Function(closure)}
}
}
클로저는 이렇게 돌아가지 않을까 싶습니다... 이 부분은 확신이 없네요
자신으로부터 프로토타입을 쭈욱 타고 올라가 prototype이 null이 될때까지 탐색 하는 것 입니다.
위의 케이스는 scope chain을 하다가 최상단에도 없으니 global 객체의 porototype을
탐색하여 결국 찾아내는 특이한 케이스 입니다.
만일 this 없이 일반 객체의 prototype을 사용 했을 때는 탐색이 되지 않습니다.
끝까지 가도 그 변수는 없고, global객체의 prototype에도 없을 테니깐요
function Test(){
this.a = 0;
}
Test.prototype.test = function(){
console.log(a) // a not defined
console.log(this.a) // 0 만일 this.a가 없으고 부모가 있다면 부모의 prototype을 탐색.. prototype이 null 될 때 까지
}
const t = new Test():
t.test();
https://homoefficio.github.io/2016/01/16/JavaScript-%EC%8B%9D%EB%B3%84%EC%9E%90-%EC%B0%BE%EA%B8%B0-%EB%8C%80%EB%AA%A8%ED%97%98/
https://velog.io/@paulkim/e
https://stackoverflow.com/questions/23948198/variable-environment-vs-lexical-environment
https://meetup.toast.com/posts/118
https://meetup.toast.com/posts/123
https://meetup.toast.com/posts/129
http://www.ecma-international.org/ecma-262/6.0/#sec-environment-records
https://dev.to/shoupn/javascript-code-nesting-and-lexical-environments-explained-3bi4
오류가 있으면 언제든지.. 감사합니다.
감사합니다.!
와 이렇게 자세하게 분석한 글 ... 감사합니다.
렉시컬 , 스코프체인, 프로토타입 체인의 우선순위에 대해서 알아보고 있었는데
엄청 깔끔하게 정리해주셨네요 저도 나중에 해봐야겠네요 감사합니다.