javascript执行上下文、作用域与闭包(第六篇)

终于讲到闭包了,当你在百度上搜索闭包时,你会被搜索出来的结果吓一跳,我的天,为什么说得都不一样?直到把所有的解释都看过了,我就只想说一句,到底谁说的是对的…

在这么多的不同解释里,我认真思考了很久,到底该相信谁?最后我选择相信大道至简,因为我始终觉得理论来源于实践,而实践一定不是在象牙塔里,而是可以摸得到的简单的东西。

下面就来讲最原始的闭包的示例:

function fn(){var max=10;return function bar(x){if(x>max){alert(x);}}}var f1=fn();f1(15);//15

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

如上代码,bar函数作为返回值,赋值给f1变量。执行f1(15)时,就相当于执行bar(15),沿着作用域链取到fn作用域下的max变量的值。

这已经产生了一个最基本的闭包,用自然语言描述的话就是:

(1)定义普通函数 A

(2)在 A 中定义普通函数 B

(3)在 A 中返回 B

(4)执行 A, 并把 A 的返回结果赋值给变量 C

(5)执行 C

而它的形式就是用“return”作为桥梁,链接A外的变量C和A内的变量B。

用一个归纳的话说就是:

当一个内部函数被其外部函数之外的变量引用时,就形成了一个闭包

如果你认为这就是闭包的全部,那你就有些狭隘了。

下面一个例子,就展示了这个狭隘之处:

function A(){    var count=0;    function B(){        count++;        alert(count);    }    return B;} var c=A(); c();//1 c();//2 c();//3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

那么你就会惊奇于闭包还有如此神秘的一面,其实对于这一面,网上有很多解释,解释得五花八门,但大都没解释到本质上。

其实这一系列的文章的标题都是“javascript执行上下文、作用域与闭包”,说明闭包与执行上下文,作用域是有紧密联系的,下面就来演示一下闭包那神秘的一面的本质。

咱们可以拿本文的第一段代码(稍作修改)来分析一下。

function fn(){var max=10;return function bar(x){if(x>max){alert(x);}}}var f1=fn(),max=100;f1(15);//15

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

我们来一步一步揭开那神秘的面纱:

在这之前,告诉大家一个很重要的东西—-我们在前面讲执行上下文栈时当一个函数被调用完成之后,其执行上下文将被被弹出,即销毁,其中的变量也会被同时销毁。

但我们要铭记:在闭包里,函数调用完成之后,其执行上下文环境不会立即被销毁。(这句话是不正确的,但这里读者可以先用这个错误的解释去看下面的步骤,先对闭包形成的原因有一个大致的了解,最终正确的理解在 厚积薄发—从此再也不用担心闭包问题

第一步,代码执行前生成全局上下文环境,并在执行时对其中的变量进行赋值。此时全局上下文环境是活动状态:

第二步,执行第17行代码时,调用fn(),产生fn()执行上下文环境,压栈,并设置为活动状态。

第三步,执行完第17行,fn()调用完成。按理说应该销毁掉fn()的执行上下文环境,但是因为执行fn()时,返回的是一个函数。函数的特别之处在于可以创建一个独立的执行上下文,当代码执行到return时,按理说应该把fn()的执行上下文销毁,但是由于return的bar()存在对fn()上下文的引用,(因为存在对变量max的需要)所以不能将其销毁,这里就要提到js的垃圾回收机制,当一个函数不存在外部对它的引用的时候,就自动将其销毁。这里存在对把不能把fn()上下文销毁。

第四步,执行到第18行时,全局上下文环境将变为活动状态,但是fn()上下文环境依然会在执行上下文栈中。另外,执行完第18行,全局上下文环境中的max被赋值为100。如下图:

第五步,执行到第20行,执行f1(15),即执行bar(15),创建bar(15)上下文环境,并将其设置为活动状态

执行bar(15)时,max是自由变量,需要向创建bar函数的作用域中查找,找到了max的值为10,

这里的重点就在于,创建bar函数是在执行fn()时创建的。fn()早就执行结束了,但是fn()执行上下文环境还存在与栈中,因此bar(15)时,max可以查找到。如果fn()上下文环境销毁了,那么max就找不到了。

可以看到,使用闭包会使变量保存在内存中,但是缺点就是会增加内存开销。

在网上有些资料解释闭包的主要用途有两个,一个是可以使外部变量访问到一个函数的内部变量,一个是使变量保存在内存中。其实这句话不太贴切,正确的说法应该是:使外部变量访问到一个函数的内部变量是闭包的形式,使变量保存在内存中是闭包的工作原理。

到这里,如果觉得有种恍然大悟的感觉,不妨试一试下面的例子

function A(){    var count=0;    function B(){        count++;        alert(count);    }    return B;} var c=A(); c();//1 c();//2 c();//3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

大家可以试一试解释为什么三次调用c(),结果分别是1,2,3呢?

如果还有些不懂,我会在下一篇里详细讲一下我的理解。


本文参考了王福朋老师的深入理解javascript原型和闭包(15)——闭包

(0)

相关推荐

  • 25.JavaScript执行上下文

    JavaScript执行上下文 1.this指向 1).直接调用函数,this指向全局对象 2).在函数外,this指向全局对象 3).通过对象调用或new一个函数,this指向调用的对象或新对象 2 ...

  • javascript中的闭包这一篇就够了

    前端技术优选 今天 以下文章来源于程序员成长指北 ,作者koala 程序员成长指北专注 Node.js 技术栈分享,从 前端 到 Node.js 再到 后端数据库,祝您成为优秀的高级 Node.js ...

  • 水产养殖规范用药,渔业部门将会如何执行?沈锦玉提出六不用

    为加强水产养殖用兽药.饲料和饲料添加剂等投入品管理,依法打击生产.进口.经营和使用假.劣水产养殖用兽药.饲料和饲料添加剂等违法行为,保障养殖水产品质量安全,加快推进水产养殖业绿色发展,并根据相关法律法 ...

  • 化解执行难的“降龙十八掌”(第六招)——“首先查封PK优先债权”

    导读 今天,万益案件执行部将使出化解执行难的"降龙十八掌"第六招--"首先查封PK优先债权",为您详细介绍执行程序中,当被执行人的财产存在优先债权时,是不是采取 ...

  • 执行异议申请书六篇

    当下市场经济活跃,交易频繁,我们每个人都可能要用到申请书,通过申请书,我们可以提出自己的请求.写起申请书来就毫无头绪?以下是小编帮大家整理的执行异议申请书6篇,仅供参考,希望能够帮助到大家. 执行异议 ...

  • 前端js中var的执行上下文

    //变量提升:var声明的变量(除函数内),值提升变量的声明. // console.log(i); // var i=0; // console.log(i); //函数提升:字面量声明的函数,提升 ...

  • JavaScript执行机制浅谈

    JS是单线程 JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事. 这是因为Javascript这门脚本语言诞生的使命所致--JavaScript是为处理页面中用户的交互, ...

  • 前端面试题整理——作用域和闭包

    什么是闭包,闭包的表现形式: // 作用域应用的特殊情况,有两种表现: // 函数作为参数被传递 // 函数作为返回值被返回 // 函数作为返回值 function create() { let a ...

  • 什么是执行上下文

    网上关于执行上下文的文章有很多,关于什么是执行上下文,很多文章说得很清晰. 我说一下自己的理解. 执行上下文包含三个东西: VO this [[scope]] 为什么包含这三个东西呢?首先我们要明白, ...