作用域
局部作用域
- 函数作用域
函数内部声明的变量只能在函数内部被访问,外部无法访问
函数执行完了之后内部变量就清空了
- 块作用域
被 {} 包裹的代码称为代码块,代码块内部声明的变量外部有可能无法访问
这个可能是由 var 造成的,var 声明的变量不会产生块级作用域,也就是说外部也可以访问
全局作用域
就是最外层的区域
作用域链
作用域本质是底层的变量查找机制
函数被执行时会优先在当前函数作用域内查找变量
如果当前函数作用域找不到则会依次向上查找父级作用域直到全局作用域
垃圾回收机制
js中内存的分配与回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收
由此引出了内存的生命周期
- 内存的生命周期
- 内存分配
当我们声明变量、函数、对象的时候,系统会自动为我们分配内存
- 内存使用
读写内存,也就是使用变量、函数等
- 内存回收
使用完毕,由垃圾回收器自动回收不再使用的内存
全局变量一般不会回收(关闭页面时回收)
局部变量不使用了就会被自动回收掉
内存泄漏:程序中分配的内存由于某种原因未释放或无法释放就称为内存泄漏
- 栈与堆
-
栈:由操作系统自动分配释放,函数的参数值、局部变量等,基本数据类型在栈里面
-
堆:一般由人分配释放,若人不释放,则由垃圾回收机制回收,复杂数据类型在堆里面
- 垃圾回收算法
- 引用计数法
大体上为:看一个对象是否有指向它的引用,没有引用了就回收对象
算法:
跟踪记录被引用的次数
如果被引用了则增加记录的次数
如果减少了引用则次数相应减少
如果引用次数是0,则释放内存
如
const arr=[1,2,3] //此时堆区域存放了复杂数据类型——数组,arr指向数组,也就是arr是对数组的引用
arr = 1 //对arr进行赋值,此时arr不再指向数组,也就是arr不再是对数组的引用,此时对数组[1,2,3]的引用是0,则被自动回收
弊端:
嵌套引用(循环引用)
如果两个对象相互引用,即使它们不再使用,也不会被自动回收,从而导致内存泄露
如
const o1 = {}
const o2 = {}
o1.a=o2
o2.a=o1 //o1与o2对象相互引用,导致即使不再使用它们,但是因为它们之间有互相引用,所以引用次数不会为0,就无法被自动回收
现代的浏览器已经不再使用引用计数法了,而是使用基于标记清除算法的某些算法
- 标记清除法
核心:
寻找无法到达的对象,进行回收
从根部(在JS中就是全局对象)出发定时扫描内存中的对象。凡是能从根部到达的对象,都是还需要使用的
那些无法由根部出发触及到的对象被标记为不再使用,稍后进行回收