var message = "hello message"
function foo() {
console.log(message)
return message
var message = "hello world"
}
foo()
上述代码执行结果:undefined
过程分析:
1.js代码执行之前会经过parse(词法分析)变成AST,这个过程会生成Global Object(GO),全局定义的变量、函数等都会被放入GO中,但并不会赋值。代码分析过程中检测到foo为函数,就会在堆内存中开辟出一块内存地址用来存放其父级作用域和其代码块 。
GO = {message: undefined, foo: 0xa00 }
0xa00 --> parent scope: GO,代码体
parse过程中发现函数执行代码,就会生成这个执行函数(也就是foo函数)所对应的Activation Object(AO),AO中会包含形参、arguments、函数定义和指向函数对象、定义的变量。
AO = {..., message: undefined}
2. js引擎内部有一个执行上下文栈(ECS),用于执行代码的调用栈。
3. 执行全局代码时会创建一个全局执行上下文(GEC),GEC被放到ECS中执行,GEC中包含Variable Environment(VE),VE指向GO,开始执行全局代码,此时将GO中的message赋值为hello message。
4. 执行过程中遇到函数,根据函数体创建一个函数执行上下文(FEC),并将其压入到ECS中执行,FEC中也包含VE,且VE指向AO,函数执行,打印message,在自身作用域中寻找message变量,找到后打印undefined,return函数执行完毕,FEC出栈。
5. 全局代码执行完毕,GEC出栈。