代码执行前内存做的事情
1.初始化全局对象
2.执行上下文
3.
函数是先被声明
4.当全局代码被执行的时候,vo就是go对象了
函数如何被执行
一、函数调用执行过程
var message = "Hello Global"
function foo() {
console.log(message)
}
function bar() {
var message = "Hello Bar"
foo()
}
bar()
代码执行都需要加入调用栈(ECStack)中执行,所以先有调用栈
编译阶段,就会先创建一个GO对象(Global Object),里面有window、string等等
除了有本来的还要对代码进行编译,会发现还有message,此时为undefined,
再往后走,还有函数foo,是函数 这时就会在内存中创建一块空间,用来存储foo函数对象,
空间有自己的内存地址,这个函数对象包含:父级作用域、函数代码执行体等
其中这个时候就确定了他的父级作用域就是上一层GO(全局),即编译的时候就确定了父级作用域
有函数的话继续重复上面
然后开始执行全局代码,会创建一个全局执行上下文
全局上下文会包含VO对象,即这里指向GO
执行代码之前:
执行代码:
1.给message赋值:“Hello Global”
2.函数定义都编译了跳过
3.执行bar()函数
4.因为是函数执行,所以创建函数执行上下文(FEC)
5.函数执行上下文也是里面有VO对象,这个时候他就是AO,所以创建AO对象
(每一个执行上下文会关联到一个变量对象VO,源代码中的变量和函数声明会被作为属性添加到VO中,对于函数来说,参数也会被添加到VO中。
新的ECMA规范中,我们前面的变量对象VO已经有另外一个称呼了变量环境 VE)
6.这个时候代码还没执行,所里面有message:undefined,
7.AO完成开始执行代码,给message赋值“Hello Bar”,执行foo()
8.foo()有事函数执行,所以在调用栈中再创建foo的函数执行上下文,创建AO对象,这个时候没没东西为空。AO完成执行代码,console.log(message),按照作用域链查找要打印的message,作用域链scope chain:VO+parentScoipe,foo的父级作用域是GO,开始编译的时候就已经确定,所以函数作用域跟定义位置有关系,跟调用的位置没有关系,
1.编译
执行函数就会在函数调用栈中创建一个函数执行上下文(FEC),函数执行上下文中有自己的AO,所以会创建一个AO对象,编译里面的东西
函数执行上下文(FEC)里除了VO对象还有scope chain作用域链,还有this,运行的时候绑定
foo执行之前,会先创建AO对象(Activation Object),AO对象中默认情况下,里面的mun、m、n都是undefined,bar是函数,也会开辟一块存储空间,包括内存地址、父级作用域、函数代码执行体,bar:oxboo,保存的也是内存地址
2.执行
执行完,函数执行上下文就会从调用栈中弹出来销毁
作用域链
函数在定义时就确定了作用域链,跟他在那调用没有关系,跟在哪里定义有关系
作用域提升 面试题
1.200,
2.undefined 200
此题结果为100,虽然为语法错误,但是 没有用var定义m,js引擎会默认m为全局定义的
function foo() {
m = 100
}
foo()
console.log(m)
function foo() {
var a = b = 10
// => 转成下面的两行代码
// var a = 10
// b = 10
}
foo()
// console.log(a) //a is not defined,这行不注释掉的话,报错,不会执行打印b
console.log(b) //10
二、内存管理
不管以什么样的方式来管理内存,内存的管理都会有如下的生命周期:
第一步:分配申请你需要的内存(申请);
第二步:使用分配的内存(存放一些东西,比如对象等);
第三步:不需要使用时,对其进行释放;
JS内存管理
JavaScript会在定义变量时为我们分配内存。
JS对于基本数据类型内存的分配会在执行时, 直接在栈空间进行分配;
JS对于复杂数据类型内存的分配会在堆内存 中开辟一块空间,并且将这块空间的指针返 回值变量引用
垃圾回收的英文是Garbage Collection,简称GC;
对于那些不再使用的对象,我们都称之为是垃圾,它需要被回收,以释放更多的内存空间
当一个对象有一个引用指向它时,那么这个对象的引用就+1,当一个对象的引用为0时,这个对象就可以被销毁掉;
这个算法有一个很大的弊端就是会产生循环引用;
这个算法是设置一个根对象(root object),垃圾回收器会定期从这个根开始,找所有从根开始有引用到的对象,对于哪些没有引用到的对象,就认为是不可用的对象;
这个算法可以很好的解决循环引用的问题;