2-函数执行原理,作用域链,内存管理

109 阅读5分钟

这一集讲了:函数执行过程原理,作用域链原理 提升作用域应该了解了,变量名提升上去但是不赋值,执行时候才赋值,但是函数就不一样,到了函数这里按道理应该是,foo: undefined,这样,但是他会把这个函数放在内存中,然后把undefined替换成内存地址

如果这个函数里还有函数,那就先预编译(❓疑问不太明白预编译具体是什么样),到了这个外层函数执行的时候,再去编译这样子。

然后函数开始执行(栈底那个foo)找foo这个函数,顺着VO => GO,找到内存地址,然后创建一个 函数执行上下文FEC(我觉得是创建这一步就编译内嵌的函数吧),里面还有个VO,不再指向GO了,而是新建一个AO动态对象,还有scope作用域加上父级作用域,然后在这里面开始执行函数里面的代码,顺着作用域链去找变量。 调用内嵌函数的时候,顺着找到内存地址,然后创建函数执行上下文,套娃吗,再来一遍刚才的操作,函数执行完后,函数执行上下文就会出栈(扔掉),对应的AO没有引用指向它了也会被销毁,还有保存的函数体那个也会销毁,但是要是写的是闭包,还有别的引用引向它,就不会销毁(还没讲到)。

函数执行上下文里的VO和作用域链那一块,其实还有个东西:this,不过是在运行的时候进行绑定,然后还有个东西:arguments

函数调用函数

一道题,下面的输出结果是什么

var message = 'hello Global'function foo () {
  console.log(message)
}
​
function bar () {
 var message = 'hello bar'
 foo()
}
​
bar()

结果是:hello Global,因为bar里的message是在bar里面定义的,和外面的没有关系,所以foo函数打印的message是foo的上一层全局对象的message。 老师推荐书籍:强烈推荐红宝书,和你不知道的JavaScript(在语言设计层面讲的深)

闭包定义

休息一下

上面讲的都是老版本的东西了,es5之前的。 关于VO,有了变化:VO从对象变成了Variable Environment(变量环境);之前是把变量和函数的参数作为属性添加到VO,现在是绑定到变量环境作为环境记录

这时候不一定是对象了,可以用map等等自由选择❓疑问这样会有什么区别吗

2点了02:04, 看到了2h处,还有1h,留给明天看吧。

用node来跑代码比较快,直接在vscode里打开终端看结果,比拉到html再打开浏览器方便多了。(不过要调试的话估计还得去浏览器里🤔)

[[2022-08-04]]继续继续

function foo() {     //这里的a变量会写进AO吗?   答案:会
    console.log(a)
    return           //这里return不管他,执行函数阶段才看这个
    var a = 100      //所以仍然会把这个a提出到AO动态对象并定义undefined,正常流程
}

不写var就变成全局变量-的原因

function foo () {
    m = 100
}
foo()
console.log(m)    //100

这种情况,因为没有用var之类的声明,就不会把m放进AO里,执行的时候就顺着去上一级(这里也就是GO)去找,也找不到,就到最头GO里面定义一下m(我的理解)

关于 var a = b = 10

var a = b = 10
//相当于👇
var a = 10      
b = 10   //全局了这个

顺序是,10赋值给b,b赋值给a

内存管理

有些编程语言需要我们手动管理内存,有的语言自动帮我们管理内存

内存管理的生命周期
  1. 分配申请需要的内存
  2. 使用分配的内存,存东西,对象等
  3. 不需要时,释放

手动管理内存:c、c++,OC-早期ios的 自动管理:java、JavaScript、python、Swift、Dart

内存分配方式 -JavaScript

基本数据类型 - 直接在栈空间进行分配 复杂数据类型 - 堆内存中开辟一块空间,将这块空间的指针返回值变量引用 这跟线,就是引用的意思,(在c语言里就是指针)

js的垃圾回收机制-GC(Garbage Collection)

用js的时候,申请内存可以不用管,释放内存的时候 一般 也是不用管,闭包的时候要管,会有内存泄漏(内存泄漏是啥)
什么是垃圾?那些不再使用的对象
GC怎么知道哪些对象是垃圾呢?

垃圾回收器的算法-GC算法

有两个算法:

  1. 引用计数: 想到了在VS里写c#时候看见每个函数上面都会写 0个引用 1个引用的。
    弊端: ab之间互相引用,就是无限循环了
    2.标记清除 设置一个根对象root object(在这里就是GO),GC就会定期从这个根对象开始找,找所有从根对象开始引用到的对象,没有引用到的就认为是不可用对象(不可达对象)
    标记的是可以达到的对象,不可达对象到时候就要被清除了

js采用的是标记清除 (当然V8引擎里更复杂一点,用到了其他的算法,对不同的对象采用不同的算法,让效率更高)

内存泄漏:该释放的对象没有被释放掉(??这就是泄漏吗)