JavaScript中闭包的原理

作用域链

  • VO: variable object
  • AO: active object
    在讲闭包之前,我们得先讲讲作用域链,因为闭包的先决条件就是作用域链的存在。

    var color = 'red'
    function isRed() {
      return color === 'red'
    }
    console.log(isRed()) // true 

    大家都知道因为作用域链,我们可以访问到变量对象(全局对象)上的属性,但其中的原理是什么呢?

  1. 首先: 浏览器在预编译阶段会创建一个 VO 对象, VO 对象中会包含全局的方法以及属性,如果遇到方法会给方法的[[Scope]]传递当前的作用域链(scope chain),作用域链决定了上下文以及函数的执行顺序。
  2. 解析完成之后,面临的就是执行 isRed 方法,在执行该方法时,浏览器会给当前函数创建一个 AO 对象,在 AO 对象中, 它的this指向 window(严格模式为undefined), 同时会 return 一个 value。
  3. 补充:这每个执行,也是一个上下文,会复制定义时的[[Scope]],把当前的上下文push进去,放到栈顶。
    JavaScript中闭包的原理_第1张图片

闭包

讲完作用域链,就到我们的正题,闭包。
在调用函数时,浏览器会给函数创建一个执行上下问,并创建一个执行上下文,并创建作用域链。当我们有函数嵌套,并且内函数引用了外函数的变量就会产生闭包。但产生闭包的原理呢?直接上代码!!!

function myClosure() {
    var a = 1 
    return function () {
        ++a
        return a
    }
}
var myclosure = myClosure()
console.log(myclosure()) //2
console.log(myclosure()) //3
  1. 首先,浏览器在预编译阶段会创建一个 VO 对象, VO 对象中会包含全局的方法以及属性,如果遇到方法会给方法的[[Scope]]传递当前的作用域链(scope chain),作用域链决定了上下文以及函数的执行顺序。
  2. 执行 myClosure 方法,创建 AO 对象,在 AO 对象中, 它的this指向 window, 同时会 return 一个 value,因为return 的是一个function, 所以在预编译阶段,会把该方法的[[Scope]]预装上当前的作用域链,即全局上下文myClosure的函数上下文。
  3. 执行 myclosure 方法,创建 myclosure 的 AO 对象,该对象的this指向window,同时因为使用了myClosure函数的 AO 对象,所以在内存中保留着对该变量的引用(Closure 指向了myClosure),因此myClosure在被执行完成后应该被销毁的函数上下文并没有被销毁。就此,产生了闭包。
    JavaScript中闭包的原理_第2张图片

以上内容,是我结合书本和实践,理解肯定有不到位甚至错的地方,欢迎各位大佬的点评!!!

你可能感兴趣的:(javascript)