Gahing's blog Gahing's blog
首页
知识体系
  • 前端基础
  • 应用框架
  • 工程能力
  • 应用基础
  • 专业领域
  • 业务场景
  • 前端晋升 (opens new window)
  • Git
  • 网络基础
  • 算法
  • 数据结构
  • 编程范式
  • 编解码
  • Linux
  • AIGC
  • 其他领域

    • 客户端
    • 服务端
    • 产品设计
软素质
  • 面试经验
  • 人生总结
  • 个人简历
  • 知识卡片
  • 灵感记录
  • 实用技巧
  • 知识科普
  • 友情链接
  • 美食推荐 (opens new window)
  • 收藏夹

    • 优质前端信息源 (opens new window)
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Gahing / francecil

To be best
首页
知识体系
  • 前端基础
  • 应用框架
  • 工程能力
  • 应用基础
  • 专业领域
  • 业务场景
  • 前端晋升 (opens new window)
  • Git
  • 网络基础
  • 算法
  • 数据结构
  • 编程范式
  • 编解码
  • Linux
  • AIGC
  • 其他领域

    • 客户端
    • 服务端
    • 产品设计
软素质
  • 面试经验
  • 人生总结
  • 个人简历
  • 知识卡片
  • 灵感记录
  • 实用技巧
  • 知识科普
  • 友情链接
  • 美食推荐 (opens new window)
  • 收藏夹

    • 优质前端信息源 (opens new window)
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 前端基础

    • 编程语言

      • CSS

      • HTML

      • JavaScript

        • ECMAScript6入门
        • JS 手写题

        • JS技巧
        • JS 学习笔记
        • Promise then 原理分析
        • async 函数编译原理
        • 你不知道的JavaScript(上)
        • 再谈闭包
          • 前言
          • 词法环境
          • 闭包
            • 垃圾回收
          • 拓展阅读
        • 浏览器剪切板协议
        • 前端实现相对路径转绝对路径的几种方法
        • 为什么 0.._ 等于 undefined
        • 前端项目中常用的位操作技巧
        • 如何利用前端剪切板实现文件上传
        • 快速理解 JS 装饰器
        • 趣味js-只用特殊字符生成任意字符串
        • 重学 JS 原型链
        • 面试官问:怎么避免函数调用栈溢出
      • Rust

      • TypeScript

      • WebAssembly

    • 开发工具

    • 前端调试

    • 浏览器原理

    • 浏览器生态

  • 应用框架

  • 工程能力

  • 应用基础

  • 专业领域

  • 业务场景

  • 大前端
  • 前端基础
  • 编程语言
  • JavaScript
gahing
2020-01-07
目录

再谈闭包草稿

# 前言

闭包很简单,一个函数与创建该函数的词法环境,就是一个闭包,该词法环境包含了闭包所能访问的所有局部变量

闭包又很难,外部词法环境被销毁,而自身又保持对外部词法环境变量的引用,执行引擎对堆栈的处理是怎样的

本文将对以下几个问题进行解析

  1. 词法环境
  2. 闭包中保存的引用是什么

# 词法环境

函数声明和匿名函数表达式不会创建新的变量环境,其变量环境指向函数创建时的变量环境

命名函数表达式会创建一个新的变量环境,新的变量环境 outer 指向旧变量环境,环境记录指向所赋值的变量

每个大括号会生成一个词法环境,所以 for 循环中 let 定义的 i 属于每个词法环境的元素

词法环境包括:

  • 环境记录
  • 对外部的引用

环境记录初始化是在定义时(代码执行前)做的,扫描代码并把变量声明记录到环境记录中,所以声明函数时,里面 let 重复定义在声明时就报错了

同时初始化的时候会设置外部的引用,指向上一层的词法环境

https://juejin.im/user/5757d748207703006fd9deb2

# 闭包

闭包:把闭包函数放入了执行调用栈,生成闭包函数的函数在生成闭包函数后就弹出执行栈了,闭包函数内对上层函数的访问其实是对内存中元素的访问,所以生成闭包的函数不能有其他地方的引用,否则会造成垃圾回收无法回收

function test(){
  let a = 1
  return function(flag){
    if(flag){
      console.log(a)
    }
  }
}
console.dir(test())
1
2
3
4
5
6
7
8
9
function test(){
  let a = 1
  setTimeout(function(){
    console.log(a)
  })
}
test()
1
2
3
4
5
6
7

创建setTimeout函数时,内部有对外部词法环境属性的引用,但是都是属于同个词法环境

for(var i=0;i<10;i++){
  setTimeout(function(){
    console.log(i)
  })
}
1
2
3
4
5

# 垃圾回收

由于某个闭包变量被使用,导致上层词法环境没有被回收,这是因为返回的函数中会挂载上 [[scopes]].closure 外部词法环境引用

浏览器开启内存变化工具查看

function test(){
  let a = Array(100000).fill(0)
  return function(){
    a = null
  }
}
let s = test()
console.dir(s)
s()
console.dir(s)
1
2
3
4
5
6
7
8
9
10

先升高,解除引用后,内存降低

但是 v8 引擎有做优化。。其实没那么简单。。,没有显示的使用,不会去创建这个 a 数组

# 拓展阅读

https://blog.csdn.net/weixin_40013817/article/details/103287271

编辑 (opens new window)
上次更新: 2024/09/01, 23:56:56
你不知道的JavaScript(上)
浏览器剪切板协议

← 你不知道的JavaScript(上) 浏览器剪切板协议→

最近更新
01
浅谈代码质量与量化指标
08-27
02
快速理解 JS 装饰器
08-26
03
Vue 项目中的 data-v-xxx 是怎么生成的
09-19
更多文章>
Theme by Vdoing | Copyright © 2016-2024 Gahing | 闽ICP备19024221号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式