「面试梳理-JS」闭包

161 阅读4分钟

你对js「闭包」了解多少?

闭包是什么?

什么情况会产生闭包?

闭包实际应用场景?

闭包产生的变量如何回收?

提升-预编译?

提升-执行上下文?

提升-词法作用域(静态作用域)?

提升-自由变量?

提升-作用域链?

提升-作用域?

提升-变量?

1. 变量?

  • 变量含义: 用于存放数据的「容器」,通过「变量名」获取数据,存放在「内存」中。 变量.png
  • 变量使用分两步:「声明变量」、「赋值」
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. 新生代(新生代互换),老生代(标记清除)