0

0

JS闭包随笔

舍。

舍。

发布时间:2017-08-11 14:57:53

|

1272人浏览过

|

来源于php中文网

原创

  开始正式介绍之前先看一个比较有难度的关于闭包的面试题:
      function fun(n,o) {
          console.log(o)  
          return {
            fun:function(m){ 
                return fun(m,n);
            }
          };
        }
        var a = fun(0);  a.fun(1);  a.fun(2);  a.fun(3);
        var b = fun(0).fun(1).fun(2).fun(3);
        var c = fun(0).fun(1);  c.fun(2);  c.fun(3);
        //问:三行a,b,c的输出分别是什么?
  
  (原文链接:http://www.cnblogs.com/xxcanghai/p/4991870.html)
  这道题是个人拿到手都会感到棘手,尤其对于一些基础不扎实的新手,看着看着就看晕了,我大体解释一些这个fun函
干了一些什么事(文章最后再分析一下这个): 首先,打印了一下他的第二个参数,然后return了一个对象,这个对象有一个方法fun,然后这个方法re
turn了fun(m,n)--最外层函数的执行结果;大体弄懂基本的流程,就可以大概分析一下了,不过在讲闭包之前,还是讲一下
js的作用域链:
  每一段js代码(全局代码或函数)(注意一下这里,敲黑板!!!)都有一个与之关联的作用域链(scope chain)。这
个作用域链是一个对象列表或者链表,这组对象这组对象定义了这段代码作用域中的变量,当js需要查找变量x的值得时候,
(这个过程叫做‘变量解析(varaible resolution)’),他会从链中的第一个对象查找,如果在第一个对象中找不到就会
查找下一个,以此类推。
  在js顶层代码中,作用域链由一个全局对象组成。在不包含嵌套的函数体内,作用域链上有两个对象第一个是该函数
定义参数和局部变量的对象,第二个是全局对象。
                                   
                             --以上两段的内容来自js权威指南,就是那本犀牛书
  当定义一个函数时,它实际上保存一个作用域链。当调用这个函数时,它创建一个新的对象来存储他的局部变量,并将
这个对象添加至保存的那个作用域链上,同时创建一个新的更长的表示函数调用作用域的链。对于嵌套函数来讲每次调用
外部函数时,作用域链都是不同的,内部函数又会重新定义一遍,每次调用外部函数时,内部函数的代码都是相同的,而
关联这段代码的作用域链也不相同。    
                                                            --以上内容也是来自js权威指南,就是那本犀牛书
  大概概括一下就是每个函数会形成一条作用域链,作用域链不同,能访问到的内容也不尽相同,由于作用域链上对象的
排序关系访问变量时,可以遵循一个原则--就是就近原则。
    说完作用域之后,就来谈谈闭包吧。
  简言之,混乱的作用域链就是形成闭包的元凶。
  来一个极为简单的例子:
      var d;
      function outter(){
          var c = 0;
          console.log(c);
          d = function(){ c++; }
      }
      outter();
      d();//0
        d();//1
  为什么会这样呢? 一般而言,每次调用js函数时,都会创建一个新的对象用来保存局部变量,并把这个对象添加至作
用域链中,当函数返回之后,就从作用域链中将这个对象删除,如果不存在嵌套函数也没有其他引用指向这个绑定对象,他就
会被当做垃圾回收。如果定义了嵌套函数,每个嵌套函数都会形成自己的作用域链,并且这个作用域链指向一个变量绑定对
象,如果这些嵌套的函数对象在外部函数中保存下来,那么他们也会和所指向的变量绑定对象一样被当做垃圾回收。但是如
果将这些嵌套函数作为返回值返回,或存储在某处的属性里,就会有一个外部的引用指向这个嵌套的函数。它就不会被当做
垃圾回收,并且所指向的变量绑定对象,也不会被当做垃圾回收!
    所以在上边的代码里当调用outter之后,由于外部变量d引用了嵌套的函数,故而在outter执行完毕之后,d指向的嵌套
函数何其所指向的变量绑定对象是没有被回收的,所以c也没有回收,所以有了往后的故事。。。
  来一个闭包的英文解释(以下摘自mdn的解释):
    
    a closure is the combination of a function and the lexical environment within which that
    function was declared.

   什么意思?上边话直接翻译过来就是:闭包是一个函数和这个函数被声明的词法作用域环境的组合。
   再说一下开头说到的这道题:
   
   function fun(n,o) {
          console.log(o)  
          return {
            fun:function(m){ 
                return fun(m,n);
            }
          };
        }
        
    var b = fun(0).fun(1).fun(2).fun(3);
   我来解释一下这条语句执行时会发生的情况:
   fun(0):
   fun(0) => n = 0,o = undefined;
   console.log(o); => o = undefined;打印undefined
   return { fun: function(m){ return fun(m,n ) } };  => 定义嵌套函数,形成作用域链,并由return的对象的属性
                                                          fun引用,m = undefined,n =0 ,这条作用域链被保留
   fun(0).fun(1):
       实际上是调用返回对象的fun方法:
       function(m)  => m = 1;
       return fun(m,n) => m=1,n=0;
       再执行fun函数:
       fun(n,o) => n=1,o=0;
       console.log(o) => 打印0
       return { fun: ...return fun(m,n) }  => m = undefined,n =1; 同上,作用域链被保存
       fun(0).fun(1).fun(2):
           还是调用了返回对象的fun方法:
        function(m) => m=2
        return fun(m,n) m=2,n=1
        再调用fun(n,o) => n=2,o=1
        然后再打印o就是打印1啦。。。
        然后
        fun(0).fun(1).fun(2).fun(3);
            还是调用了返回对象的fun方法:
            function(m) => m=3
            return fun(m,n) m=3,n=2
            再调用fun(n,o) => n=3,o=2
            然后再打印o就是打印2啦。。。
        ...
    最后的b是调用了返回对象的fun方法,fun执行的时候又返回了一个对象,所以b是一个对象,里边有一个键为fun值函数的
属性,这种属性我们一般叫他方法。
  其实最后才是我要讲的重点,如果为了炫技或者条件必须得情况下,使用闭包外,闭包能避免就避免,因为只要你使用了
闭包就意味着你在内存里划出了一块地方,你的程序可能不一定会用,而电脑在运行时其他的程序却一点不能利用的空间,
对程序的性能无疑有影响。

作者最新文章

JS闭包随笔

2017-08-11 14:57

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
2026赚钱平台入口大全
2026赚钱平台入口大全

2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

33

2026.01.31

高干文在线阅读网站大全
高干文在线阅读网站大全

汇集热门1v1高干文免费阅读资源,涵盖都市言情、京味大院、军旅高干等经典题材,情节紧凑、人物鲜明。阅读专题下面的文章了解更多详细内容。

32

2026.01.31

无需付费的漫画app大全
无需付费的漫画app大全

想找真正免费又无套路的漫画App?本合集精选多款永久免费、资源丰富、无广告干扰的优质漫画应用,涵盖国漫、日漫、韩漫及经典老番,满足各类阅读需求。阅读专题下面的文章了解更多详细内容。

36

2026.01.31

漫画免费在线观看地址大全
漫画免费在线观看地址大全

想找免费又资源丰富的漫画网站?本合集精选2025-2026年热门平台,涵盖国漫、日漫、韩漫等多类型作品,支持高清流畅阅读与离线缓存。阅读专题下面的文章了解更多详细内容。

7

2026.01.31

漫画防走失登陆入口大全
漫画防走失登陆入口大全

2026最新漫画防走失登录入口合集,汇总多个稳定可用网址,助你畅享高清无广告漫画阅读体验。阅读专题下面的文章了解更多详细内容。

11

2026.01.31

php多线程怎么实现
php多线程怎么实现

PHP本身不支持原生多线程,但可通过扩展如pthreads、Swoole或结合多进程、协程等方式实现并发处理。阅读专题下面的文章了解更多详细内容。

1

2026.01.31

php如何运行环境
php如何运行环境

本合集详细介绍PHP运行环境的搭建与配置方法,涵盖Windows、Linux及Mac系统下的安装步骤、常见问题及解决方案。阅读专题下面的文章了解更多详细内容。

0

2026.01.31

php环境变量如何设置
php环境变量如何设置

本合集详细讲解PHP环境变量的设置方法,涵盖Windows、Linux及常见服务器环境配置技巧,助你快速掌握环境变量的正确配置。阅读专题下面的文章了解更多详细内容。

0

2026.01.31

php图片如何上传
php图片如何上传

本合集涵盖PHP图片上传的核心方法、安全处理及常见问题解决方案,适合初学者与进阶开发者。阅读专题下面的文章了解更多详细内容。

2

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
CSS3 教程
CSS3 教程

共18课时 | 5万人学习

PostgreSQL 教程
PostgreSQL 教程

共48课时 | 8.2万人学习

NumPy 教程
NumPy 教程

共44课时 | 3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号