乐趣区

v8原理v8中的闭包

V8 执行 JavaScript 代码,需要经过编译和执行两个阶段,其中编译过程是指 V8 将 JavaScript 代码转换为字节码或者二进制机器代码的阶段,而执行阶段则是指解释器解释执行字码,或者是 CPU 直接执行二进制机器代码的阶段。

在编译 JavaScript 代码的过程中,V8 并不会一次性将所有的 JavaScript 解析为中间代码,这主要是基于以下两点:

  • 首先,如果一次解析和编译所有的 JavaScript 代码,过多的代码会增加编译时间,这会 严重影响到首次执行 JavaScript 代码的速度,让用户感觉到卡顿。
  • 其次,解析完成的字节码和编译之后的机器代码都会存放在内存中,如果一次性解析和 编译所有 JavaScript 代码,那么这些中间代码和机器代码将会一直占用内存。

基于以上的原因,所有主流的 JavaScript 虚拟机都实现了 惰性解析 。所谓 惰性解析 是指解析器在解析的过程中,如果遇到函数声明,那么会跳过函数内部的代码,并不会为其生成 AST 和字节码,而仅仅生成顶层代码的 AST 和字节码。

闭包的三个特性:

  1. JavaScript 语言允许在函数内部定义新的函数。
  2. 可以在内部函数中访问父函数中定义的变量。
  3. 因为函数是一等公民,所以函数可以作为返回值。

v8 的预解析器
V8 引入预解析器,比如当解析顶层代码的时候,遇到了一个函数,那么预解析器并不会直 接跳过该函数,而是对该函数做一次快速的预解析,其主要目的有两个:

  1. 是判断当前函数是不是存在一些语法上的错误。
  2. 是检查函数内部是否引用 了外部变量,如果引用了外部的变量,预解析器会将栈中的变量复制到堆中,在下次执行到 该函数的时候,直接使用堆中的引用,这样就解决了闭包所带来的问题。
退出移动版