JavaScript闭包(一)——实现

简介: 闭包的官方的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

闭包的官方的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

通俗点的说法是:

  1. 从理论角度:所有的函数。因为它们都在创建的时候就将上层上下文的数据保存起来了。哪怕是简单的全局变量也是如此,因为函数中访问全局变量就相当于是在访问自由变量,这个时候使用最外层的作用域。
  2. 从实践角度:以下函数才算是闭包:
           即使创建它的上下文已经销毁,它仍然存在(比如,内部函数从父函数中返回)
           在代码中引用了自由变量(自由变量:是指在函数中使用的,但既不是函数参数也不是函数的局部变量的变量)


function testFreedom() {
            var freedomVar = 1;
            function inner(param) {
                echo(pclosure1, param + freedomVar);//将结果打印到pclosure1中
            }
          return inner;
        }

对于inner函数来说,freedomVar就属于自由变量。

 

一、一个实现


<p id="closure1" style="color:red"></p>


function echo(p, html) {
            p.innerHTML += html + '<br/>';
        }
     function closure() {
            var innerVar = 0;
            function inner() {
                return ++innerVar;
            }
            return inner;
        }
        var quote = closure();
        echo(pclosure1, quote());//1
        echo(pclosure1, quote());//2

1、第一次quote函数的结果为1,第二次为2

2、inner嵌套在函数closure内部;函数closure返回函数inner

3、结合上面的闭包实践角度特点,可以得出closure是一个闭包

4、函数closure在返回后不会被GC回收,原因如下:

  1. closure返回函数inner的引用给quote
  2. 函数inner的作用域链包含了对函数closure的活动对象(activation_1)的引用,如下图所示。
  3. inner可以访问到closure中定义的所有变量和函数
  4. 函数inner被quote引用
  5. 函数inner又依赖函数closure



image.png


二、大致的作用域图


image.png

 


三、closure里面的大致执行步骤


1) 初始化Global Object即window对象,Variable Object(全局执行环境中的可变对象)为window对象本身。创建Scope Chain对象,假设为scope_1,其中只包含window对象

2) 扫描JavaScript源代码,从结果中可以得到定义的变量名、函数对象。按照扫描顺序:

  1. 发现函数closure的定义,使用这个定义创建函数对象,传给创建过程的Scope Chain为scope_1。将结果添加到window的属性中,名字为closure,值为返回的函数对象
  2. 发现变量quote,在window对象上添加quote属性,值为undefined

3) 执行函数closure,得到返回值:

  3.1 创建Activation Object,假设为activation_1;创建一个新的Scope Chain,假设为scope_2,scope_2中第一个对象为activation_1,第二个对象为window对象

  3.2 处理参数列表。创建arguments对象并进行设置,将arguments设置为activation_1的属性

  3.3 对closure的函数体执行类似步骤2的处理过程:

  1. 发现变量innerVar,在activation_1对象上添加innerVar属性,值为undefined
  2. 发现函数inner的定义,使用这个定义创建函数对象,传给创建过程的Scope Chain为scope_2(函数closure的Scope Chain)。将结果添加到activation_1的属性中,名字为inner,值为返回的函数对象。inner的内部 [[Scope]]就是scope_2

  3.4 执行innerVar赋值语句,赋值为"0"

  3.5 执行inner

  1. 创建Activation Object,假设为activation_2;创建一个新的Scope Chain,假设为scope_3,scope_3中第一个对象为activation_2,接下来的对象依次为activation_1、window 对象(取自fn2的[[Scope]],即scope_2)
  2. 处理参数列表。因为inner没有参数,所以只用创建arguments对象并设置为activation_2的属性
  3. 对inner的函数体执行类似步骤2的处理过程,没有发现变量定义和函数声明
  4. 执行函数体。对任何一个变量引用,从scope_3上进行搜索,这个示例中,innerVar将在activation_1上找到
  5. 返回inner的返回值

  3.6 返回结果

4) 打印结果

相关文章
|
2月前
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript中的闭包:原理与实战
【10月更文挑战第12天】深入理解JavaScript中的闭包:原理与实战
|
1月前
|
JavaScript 前端开发
js 闭包的优点和缺点
【10月更文挑战第27天】JavaScript闭包是一把双刃剑,在合理使用的情况下,它可以带来很多好处,如实现数据封装、记忆功能和模块化等;但如果不注意其缺点,如内存泄漏、变量共享和性能开销等问题,可能会导致代码出现难以调试的错误和性能问题。因此,在使用闭包时,需要谨慎权衡其优缺点,根据具体的应用场景合理地运用闭包。
118 58
|
1月前
|
缓存 JavaScript 前端开发
js 闭包
【10月更文挑战第27天】JavaScript闭包是一种强大的特性,它可以用于实现数据隐藏、记忆和缓存等功能,但在使用时也需要注意内存泄漏和变量共享等问题,以确保代码的质量和性能。
40 7
|
1月前
|
自然语言处理 JavaScript 前端开发
JavaScript闭包:解锁编程潜能,释放你的创造力
【10月更文挑战第25天】本文深入探讨了JavaScript中的闭包,包括其基本概念、创建方法和实践应用。闭包允许函数访问其定义时的作用域链,常用于数据封装、函数柯里化和模块化编程。文章还提供了闭包的最佳实践,帮助读者更好地理解和使用这一强大特性。
23 2
|
1月前
|
存储 缓存 自然语言处理
掌握JavaScript闭包,提升代码质量与性能
掌握JavaScript闭包,提升代码质量与性能
|
1月前
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript中的闭包(Closures)
深入理解JavaScript中的闭包(Closures)
|
1月前
|
存储 自然语言处理 JavaScript
深入理解JavaScript的闭包(Closures)
深入理解JavaScript的闭包(Closures)
33 0
|
2月前
|
设计模式 JavaScript 前端开发
探索JavaScript中的闭包:从基础概念到实际应用
在本文中,我们将深入探讨JavaScript中的一个重要概念——闭包。闭包是一种强大的编程工具,它允许函数记住并访问其所在作用域的变量,即使该函数在其作用域之外被调用。通过详细解析闭包的定义、创建方法以及实际应用场景,本文旨在帮助读者不仅理解闭包的理论概念,还能在实际开发中灵活运用这一技巧。
|
2月前
|
缓存 JavaScript 前端开发
深入了解JavaScript的闭包:概念与应用
【10月更文挑战第8天】深入了解JavaScript的闭包:概念与应用
|
2月前
|
自然语言处理 JavaScript 前端开发
Javascript中的闭包encloure
【10月更文挑战第1天】闭包是 JavaScript 中一种重要的概念,指函数能够访问其定义时的作用域内的变量,即使该函数在其词法作用域之外执行。闭包由函数及其词法环境组成。作用域链和词法作用域是闭包的核心原理。闭包常用于数据隐藏和封装,如模块模式;在异步操作中也广泛应用,如定时器和事件处理。然而,闭包也可能导致内存泄漏和变量共享问题,需谨慎使用。