你对js「闭包」了解多少?
闭包是什么?
什么情况会产生闭包?
闭包实际应用场景?
闭包产生的变量如何回收?
提升-预编译?
提升-执行上下文?
提升-词法作用域(静态作用域)?
提升-自由变量?
提升-作用域链?
提升-作用域?
提升-变量?
1. 变量?
- 变量含义: 用于存放数据的「容器」,通过「变量名」获取数据,存放在「内存」中。
- 变量使用分两步:「声明变量」、「赋值」
var bianliang // 声明变量
bianliang = '变量' // 赋值
var chushihua = '初始化' // 声明变量+赋值 = 「变量的初始化」
2. 作用域?
-
作用域: 代表「某个变量」的合法使用范围
-
分三类:「全局作用域」「函数作用域」「块级作用域(es6新增)」
「全局作用域」: 块级作用域之外 或 单个js文件, 对应「全局变量」
「函数作用域」:函数内部,对应「局部变量」
「块级作用域」:{}包含起来的, 对应「局部变量」
-
目的: 减少命名冲突,提高程序可靠性
3. 作用域链?
- 作用域链:在当前作用域中没有找到使用的变量,就会一层一层往上查找,直到找到全局作用域,找到为止,找不到就会报错xx undefined
function a() { // 外部函数
var bianliang = '变了'
function b() {
function c() { // 内部函数
alert(bianliang)
}
}
}
4. 自由变量?
- 自由变量: 某个变量,在当前作用域「没有定义」,但是「被使用了」;于是沿着「作用域链」向上查找,直到找到全局作用域,找到为止,找不到就会报错xx undefined
function grandfather() {
var a = ‘hello’
function father() {
var b = ‘hello2’
function son() {
console.log(a) // a就是自由变量
}
}
}
5. 词法作用域(静态作用域)?
JavaScript并不具有动态作用域, 它只有词法作用域
- 词法作用域: 定义在词法阶段的作用域,「词法阶段」是书写代码时,将变量和块级作用域写在哪里来决定的; 无论函数在哪里被调用,它的词法作用域,由函数所处的位置决定
var value = 100
function fo() { // fo的位置往上查找
console.log(value)
}
function bar() {
var value = 2
fo()
}
bar()
// 结果: 100
执行 fo 函数,fo 函数内部查找是否有局部变量 value,如果没有,就根据书写的位置,往上查找,即 value = 100
6. 执行上下文?
- 执行上下文: js代码运行需要一个运行环境,该环境就是「执行上下文」简称AO(Activation Object)
- 执行上下文分三类:「 全局执行上下文」、「函数执行上下文」、「eval执行上下文」
- 执行上下文分两阶段:
创建阶段:
1. 创建词法环境
2. 创建变量对象,创建作用域链
3. 确认this指向,绑定this
执行阶段:
1. 变量赋值
2. 函数引用
3. 执行代码
7. 预编译?
- js执行三部曲: 「语法分析」、「预编译」、「解释执行」
- 分类: 「全局预编译」、「局部预编译」
- 执行时间: 「全局预编译(GO)」:页面加载完成时执行; 「局部预编译(AO)」:函数执行前一刻
全局预编译Golbal Object 步骤:
1. 创建一个GO对象
2.变量【声明】提升,值赋予undefined
3.函数声明提升,值赋予函数体
// 函数执行前的预编译
局部预编Activation Object 步骤:
1. 创建一个AO对象
2. 找【形参】和 变量【声明】提升,值赋予undefined
2. 将形参和实参相统一
3. 函数声明提升,值赋予函数体
8. 闭包是什么?
- 闭包含义:函数套函数, 内部函数可以访问外部函数作用域中的变量,该内部函数就是闭包
- 闭包功能:
1. 在函数外,可以访问函数内的值(return function(){});
2. 保持引用,内部函数没有执行完,外部函数变量不会被销毁(不被垃圾回收)
- 闭包特性:
1. 函数作为返回值被返回(return function(){})
2. 函数作为参数被传递
- 闭包优点:
1. 全局变量私有化(不污染全局空间)
- 闭包缺点:
1. 可能会导致内存泄漏(内部变量不会被自动化回收)
9. 什么情况会产生闭包?
- 函数内部作用域 访问函数外部作用域里的变量或参数时, 闭包就产生了
10. 闭包实际应用场景?
- 防抖和节流
- 高阶函数
- hooks的原理
- 封装一段代码,实现模块化
- 作用域链
11. 闭包产生的变量如何回收?
- 垃圾回收机制原理/概念:
1. 找出「不再使用」的变量
2. 释放掉其占用的内存
3. 它会按照「固定的时间」周期性进行
-
垃圾回收机制前提: 必须知道哪些变量没有用
-
寻找没有用的变量方法:
1. 标记清除: 「垃圾回收器」会在运行时给所有存储在内存中的变量加入标记,
2. 引用计数:记录每个值被使用的次数,被引用+1, 值改变-1,(没法解决循环引用问题)
3. 新生代(新生代互换),老生代(标记清除)