作用域链:
作用域链是底层变量查找的机制:当函数执行时,优先查找当前函数作用域中有无需要用到的变量,如果找不到,逐级查找父级,直到全局 => 嵌套关系形成作用域链,同一作用域链从小到大查找变量,子可访父,父不可访子
垃圾回收机制:
1.全局变量一般不回收
2.JS中内存的分配和回收都是自动的内存不用的时候被自动回收
3.内存泄漏现象:分配的内存因为某种原因程序未释放,或无法释放
4.栈:由系统自动分配释放函数的参数值,局部变量等,基本数据类型放到栈里
5.堆:一般由程序员分配,程序员不释放,由垃圾回收机制回收,复杂数据类型放堆里
垃圾回收的方法:
1.引用计数法:
跟踪记录引用的次数,引用一次++,减少引用--,次数归0,释放内存。
缺陷:嵌套引用 / 循环引用 / 两个变量相互引用时,不回收,导致内存泄漏
2.标记清除法:
能从根部(window)到达的,就是有用的
不能从根部到达的,就是无用的
无用的就标记,稍后回收
闭包:
1.概念 / 判断方法:
内层函数用到了外层函数的变量
2.用处:
作用1:保存私有变量,防止在该变量被恶意修改 / 污染
作用2:可以读取函数内部的变量
3.说明举例:
例子:定义一个变量ant=0,用来记录某个函数的使用次数
1.当该变量为全局变量时
html
<script>
let ant = 0
function a() {
ant++
console.log(ant);
}
a() //1
a() //2
</script>
如果程序还有其他函数,也需要用到age的值,则会受到影响,而且全局变量还容易被人修改,比较不安全。
这就是全局变量容易污染的原因,所以我们必须解决变量污染问题,那就是把变量封装到函数内,让它成为局部变量。
2.当该变量为局部变量时
html
<script>
function out() {
let ant = 0
function ini() {
ant++
console.log(ant);
}
return ini //返回ini函数
}
out()//ini函数
out()//ini函数
</script>
显而易见,每次调用out函数,都会使ant重新赋值,因此ant的值做不到增加
3.使用闭包=>跳过out直接调用内层函数时
html
<script>
function out() {
let ant = 0
function ini() {
ant++
console.log(ant);
}
return ini //返回ini函数
}
out()//ini函数
out()//ini函数
let ii = out()//ii===ini
ii()//1
ii()//2
</script>
一旦调用out(),都会使ant重新回归到初始值++的状态
而且变量ant在函数内部,不易修改和外泄,相对来说比较安全。
4.缺点
缺点1:导致变量不会被垃圾回收机制回收,造成内存消耗
缺点2:不恰当的使用闭包可能会造成内存泄漏的问题
变量/函数提升:
1.变量提升(使用var时):
即:允许变量在声明之前被访问
变量的 《声明》(不提升赋值) 会在物理层面移动到当前 《作用域》代码的最前面。
但这么说并不准确。实际上变量和函数声明在代码里的位置是不会动的,而是在编译阶段被放入内存中。
2.函数提升:
会把所有函数声明提升到当前作用域的最前面,只提声明,不提调用
函数表达式必须先声明后调用
函数的其他参数(除形参实参):
1.动态参数(箭头函数没有)arguments(伪数组=>只有下标和length)
html
<script>
function Add() {
let res = 0
for (i = 0; i < arguments.length; i++) {
res += arguments[i]
}
console.log(res);
}
Add(1, 2, 34, 5, 6, 7)
Add(3, 2, 1, 4, 53)
Add(1, 2, 3, 43, 2, 1, 2, 4)
</script>
如上方代码所示,当括号内为空时,会将参数存到一个伪数组arguments里,伪数组只能用下标和length功能
2.剩余参数 ...名字(真数组)
html
<script>
function add(a, b, ...wcnm) {
console.log(wcnm);
}
add(12, 3, 4, 5)
</script>
如上方代码所示,当括号内有 ...名字 时,多余的参数会被整合成数组 名字 保存起来