JavaScript的执行过程
初始化全局对象
js引擎会在执行代码之前,会在堆内存中创建一个全局对象:Global Object(GO)
- 该对象所有的作用域(scope)都可以访问;
- 里面会包含Date、Array、String、Number、setTimeout、setInterval等等;
- 其中还有一个window属性指向自己
执行上下文(Execution Contexts)
js引擎内部有一个执行上下文栈(Execution Context Stack,简称ECS),它是用于执行代码的调用栈。
- 那么现在它要执行谁呢?执行的是全局的代码块:
- 全局的代码块为了执行会构建一个** Global Execution Context(GEC)**;
- GEC会被放入到ECS中执行;
- GEC被放入到ECS中里面包含两部分内容:
- 第一部分:在代码执行前,在parser转成AST的过程中,会将全局定义的变量、函数等加入到GlobalObject中,但是并不会赋值;
- 这个过程也称之为变量的作用域提升(hoisting)
- **第二部分:**在代码执行中,对变量赋值,或者执行其他的函数;
- 第一部分:在代码执行前,在parser转成AST的过程中,会将全局定义的变量、函数等加入到GlobalObject中,但是并不会赋值;
认识VO对象(Variable Object)
每一个执行上下文会关联一个VO(Variable Object,变量对象),变量和函数声明会被添加到这个VO对象中。
当全局代码被执行的时候,VO就是GO对象了
全局代码执行过程(执行前)
全局代码执行过程(执行后)
函数如何被执行?
在执行的过程中执行到一个函数时,就会根据函数体创建一个函数执行上下文(Functional Execution Context,简称FEC),并且压入到EC Stack中。
_因为每个执行上下文都会关联一个VO,那么函数执行上下文关联的VO是什么呢? _
- 当进入一个函数执行上下文时,会创建一个AO对象(Activation Object);
- 这个AO对象会使用arguments作为初始化,并且初始值是传入的参数;
- 这个AO对象会作为执行上下文的VO来存放变量的初始化;
函数的执行过程(执行前)
函数的执行过程(执行后)
var message = "Global Message";
var obj = {
name: 'why',
}
function bar() {
console.log("bar function");
var address = "bar";
}
function foo(num) {
var message = "Foo Message";
bar();
var age = 19;
var height = 1.88;
console.log("foo function");
}
foo(123);
作用域和作用域链(Scope Chain)
当进入到一个执行上下文时,执行上下文也会关联一个作用域链(Scope Chain)。
作用域链是一个对象列表,用于变量标识符的求值;
当进入一个执行上下文时,这个**作用域链被创建,并且根据代码类型,添加一系列的对象; **
当一个函数定义时就创建了作用域链,查找一个函数的作用域和创建有关。
作用域提升面试题
var n = 100;
function foo() {
n = 200
}
foo();
console.log(n); // 200
![截屏2023-02-25 20.09.02.png](https://img-blog.csdnimg.cn/img_convert/02372671d54344dbe1b4ec4acd55077e.png#averageHue=#2f333f&clientId=ubb99cf0a-1314-4&from=drop&id=ub949fae6&name=截屏2023-02-25 20.09.02.png&originHeight=550&originWidth=853&originalType=binary&ratio=1.100000023841858&rotation=0&showTitle=false&size=292445&status=done&style=none&taskId=u3b4616d6-0231-4f57-bc68-66132bfc146&title=)
function foo() {
console.log(n); //undefined
var n = 200;
console.log(n); //200
}
var n = 100;
foo();
var n = 100;
function foo1() {
console.log(n); // 100
}
function foo2() {
var n = 200;
console.log(n); // 200
foo1();
}
foo2();
console.log(n); // 100
// 4.
// 代码先解析,解析的时候会先定义 ao中存在,
var a = 100;
function foo() {
console.log(a); // 100 ❌ undefined ✅
return // 代码执行时
var a = 100;
}
foo();
function foo() {
var a = b = 100;
}
foo();
console.log(a) //报错 未定义
console.log(b)
// 开发中错误写法