通过Chrome观察闭包与作用域链

1,420 阅读3分钟

*本文是在看了【js 进阶】全篇干货 !一篇文章让你彻底弄懂栈、堆、队列、执行栈、上下文、事件循环(Event Loop),之后的读后感。

  1. js数据类型
  2. 栈内存 堆内存 调用栈 函数的[[scope]]属性与作用域链
  3. 闭包&chrome查看闭包

js数据类型

原始类型

  • number
  • string
  • boolean
  • undefined
  • symbol(es10-2019)
  • bigint(es11-2020)
  • null
    typeof null // Object,是因为js中Object地址是以000开头,而null为全0
    

引用类型(唯一)Object

Object的子集:

  • Fucntion Fucntion.prototype.__proto__ === Object.prototype
  • Array Array.prototype.__proto__ === Object.prototype
  • Map Map.prototype.__proto__ === Object.prototype
  • Set Set.prototype.__proto__ === Object.prototype
  • WeakMap WeakMap.prototype.__proto__ === Object.prototype
  • WeakSet WeakSet.prototype.__proto__ === Object.prototype
  • WeakRef(es12-2021) WeakRef.prototype.__proto__ === Object.prototype
  • Math Math.__proto__ === Object.prototype
  • 特殊引用类型 Number String Boolean

堆栈与执行上下文

  • 栈(Stack):先入后出。js的栈内存用来存放原始数据类型及引用类型的指针
  • 堆(Heap): 以key-value形式存放数据,无序。js的堆内存中存放引用类型的值

在js执行时,会将待执行的函数依次进入js引擎的执行栈,执行完后再出栈,此时函数内部创建的基本类型数据会保存到栈中,引用类型数据的指针也会保存到栈中。执行完后如果不存在闭包问题,就会出栈(销毁该函数的调用栈)。

执行栈也称调用栈或执行上下文栈,可以在chrome中查看 image.png

闭包(Closure)

上面的例子,如果存在闭包例如下面这样。函数func1执行完毕出栈后,内部创建变量a应该被销毁,但是因为在func1内部创建的函数func2,使用到了func1中声明的变量,导致,及时func1的调用栈销毁了,但是因为创建func2的时候,js是将func2函数与其所在的词法作用域捆绑在一起的。所以变量a可以在func2的作用域链上找到。

image.png

Scope:是func2函数的[[scope]]属性,该属性是函数的隐藏属性,仅js引擎可访问。

Local:func2的上下文内可访问变量,里面没有a

Closure:func2被声明时的词法环境,此时因为func2中使用了func1中声明的变量,所以虽然func1的调用栈被销毁了,但是这部分数据内容(a)从func1的调用栈,转移到func2的[[scope]]属性上,使func2可以访问。

Global:为全局上下文

闭包:是由函数以及声明改函数的词法环境组合成的,闭包可以让你在一个内层函数中访问到外层函数的作用域。每当创建一个函数,闭包就会在函数创建的同时被创建出来。——————MDN

PS: 如果func2没有使用到func1中声明的变量,就不会将func1的部分词法环境(用词可能不准确)添加到func2的作用域链上,见下图。 image.png

说到底,还是要真正的理解作用域链[[scope]],闭包只是作用域链上的一个节点或几个节点