V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yantianqi
V2EX  ›  程序员

对 js 的闭包还是很迷惑?第一个用闭包了吗?

  •  
  •   yantianqi · 2017-04-03 23:34:37 +08:00 · 3946 次点击
    这是一个创建于 2550 天前的主题,其中的信息可能已经有所发展或是发生改变。
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
    </head>
    <body>
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <script>
        var lis = document.getElementsByTagName('li');
        for(var i=0; i<lis.length; i++) {
          (function(i) {//这里用闭包了吗?
            lis[i].onclick = function(e) {
              console.log(i);
            }
          })(i)
        }
    
        for(var i=0; i<5; i++) {
          (function() {
            console.log(i)//输出 0,1,2,3,4
          })()
        }
      </script>
    </body>
    </html>
    
    22 条回复    2017-04-05 13:51:42 +08:00
    billlee
        1
    billlee  
       2017-04-03 23:38:24 +08:00
    用闭包的是 })(i) 那一行, function(i) 是函数声明,你写成 function(shit) 也是一样的
    billlee
        2
    billlee  
       2017-04-03 23:40:36 +08:00
    r#1 @billlee 错错错,被你绕晕了,})(i) 也不是闭包,你就是声明了一个函数再立刻调用了
    后面那个循环才是闭包
    sneezry
        3
    sneezry  
       2017-04-03 23:50:31 +08:00 via iPhone
    不如试试 typescript ,就不用考虑闭包这些琐碎的事情了
    zbinlin
        4
    zbinlin  
       2017-04-03 23:59:39 +08:00 via Android
    第一个注释那里不是闭包,用了传参,而下面的 onclick 那里用了,还有下面第二个也用了
    EthanZ
        5
    EthanZ  
       2017-04-04 00:13:30 +08:00
    ‘用’闭包这个说法不够清楚

    楼主给的例子应该是使用了闭包的,但不是闭包的典型用法,可参考

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

    说的很清楚了
    luoyaqifei
        6
    luoyaqifei  
       2017-04-04 00:23:19 +08:00 via Android
    闭包就是捕获外部函数变量
    luoyaqifei
        7
    luoyaqifei  
       2017-04-04 00:24:47 +08:00 via Android
    所以第二个 for 里面的函数,没有传参数,但是调用了外部的 for 里的 i ,这就是闭包。
    yongSir
        8
    yongSir  
       2017-04-04 01:23:30 +08:00
    所谓闭包就是这样一种函数:
    广义上来说,如果一个函数有权访问到了其他函数作用域中的变量,那么就形成了闭包

    从这个意义上讲,诸如全局变量的访问,以及内嵌函数对外部函数的访问等等都是闭包
    甚至可以推广到任何函数都是闭包,因为都有对全局变量的访问权限, eg :

    var a = 1
    var foo = function ( console.log(a) )
    foo() // 1

    但事实上,由于这种访问是自发的天然的作用域链的延伸,所以通常我们并不把对全局变量的访问以及内层对外层的有权访问称之为闭包

    我们默认特指的闭包是这样的,比如下面代码:

    ```javascript
    function wrapFoo() {
    var wrapVar;
    var inner = function() {
    console.log(wrapVar)
    }

    }
    ```
    一个内嵌函数 inner ,具有对其外部函数 wrapFoo 所有变量的使用权,这里就是 warpVar ,如果这时在外部函数的再外层,这里就是全局环境中,实现了对内嵌函数 inner 的调用,这时就称 warpFoo 为闭包,另一个角度来说,外部函数的外面 [这里就是全局环境] ,本身是不能访问 wrapFoo 内部的变量的,通过某种方式 [如借助 return] 实现了对内嵌函数 inner 的调用,这就等于 inner 保存了 warpFoo 的变量,从而让全局中可以被访问到,这就是所谓的 close
    bombless
        9
    bombless  
       2017-04-04 01:32:01 +08:00 via Android
    一般是说你打 log 那里访问了非本地又非全局的 i 算是用到了闭包的特性。
    yongSir
        10
    yongSir  
       2017-04-04 01:34:37 +08:00
    从 js 的角度来说 如果了解 js 函数的作用域链+全局执行环境和函数执行环境
    就是能猜得出闭包
    其实是通过单独的`闭包活动对象`完成对其他`[[scop]]`的捕获
    从而达到扩展作用域的而实现的


    这些在 js 高教中讲得很清楚,建议去翻翻
    seeker
        11
    seeker  
       2017-04-04 02:23:03 +08:00
    匿名函数就是一个闭包。但是一版说闭包是因为这个匿名函数里面引用了外部的变量,也叫自由变量 free variable 。而一般的函数只有参数有影响。比如: function fun(x){return x + y} ,这个函数的 x 是参数而 y 是自由变量,跟函数在定义的时候(而不是实现的时候)的上下文 (context) 的 y 有关的,这个也叫 static scope/lexical scope (与之相对的是 dynamic scope) 。
    js 里面 for(var i = 0; i < xxx.length; i++){} 这个循环里面的 i 的作用域不是在 for 里面,而是在 for 外面,所以循环里面有函数引用了这个 i 作为自由变量的时候,可以说使用了闭包。但是就楼主的例子,那个 i 只是作为参数,并不是自由变量,所以就是一般的函数调用。
    810913195
        12
    810913195  
       2017-04-04 02:56:53 +08:00
    闭包最明显的特征:
    ①函数嵌套定义
    ②返回内层函数

    你两条都不符合。
    PythonAnswer
        13
    PythonAnswer  
       2017-04-04 04:02:57 +08:00 via Android
    更需要关心的,是,为什么要用闭包?闭包能干啥?
    iasi
        14
    iasi  
       2017-04-04 07:45:24 +08:00 via Android
    (function() {
    //这是模仿其他语言的块级作用域,跟闭包没关系
    })()
    闭包简单来说就是在一个函数内部声明一个函数,在内部函数引用外部函数的变量,就可以称为闭包了。

    一般还要在内部函数返回这个变量,不然这个闭包就没有意义了。
    Mutoo
        15
    Mutoo  
       2017-04-04 08:46:55 +08:00
    have you try these:

    ```
    for(var i=0; i<5; i++) {
    setTimeout(function() {
    console.log(i)
    }, 0)
    }
    ```

    ```
    for(var i=0; i<5; i++) {
    setTimeout(function(i) {
    console.log(i)
    }, 0, i)
    }
    ```
    Biwood
        16
    Biwood  
       2017-04-04 09:29:22 +08:00 via Android
    立即执行函数 ≠ 闭包

    闭包不需要你去实现,基本上你定义了一个函数,这个函数在存储状态中就会形成闭包, Chrome 的调试工具甚至可以让你看到函数的闭包里面包含了哪些东西
    ryd994
        17
    ryd994  
       2017-04-04 10:45:21 +08:00 via Android
    闭包你可以理解为把一部分参数绑上去,得到一个新函数
    执行这个新函数就等效为执行原函数,带绑的参数
    ipwx
        18
    ipwx  
       2017-04-04 11:02:08 +08:00
    “ In programming languages, closures (also lexical closures or function closures) are techniques for implementing lexically scoped name binding in languages with first-class functions.”

    -- https://en.wikipedia.org/wiki/Closure_(computer_programming)

    楼上所有的论断都太“主观感受”,不如从这个定义去仔细剖析。
    oaix
        19
    oaix  
       2017-04-04 12:46:28 +08:00
    function(e) {
    console.log(i);
    }
    这个是闭包
    (function() {
    console.log(i)//输出 0,1,2,3,4
    })()
    这个也是闭包
    wly19960911
        20
    wly19960911  
       2017-04-04 16:52:10 +08:00 via Android
    其实闭包不重要,重要的是闭包的作用。

    闭包函数能把引用外层 function 的参数保留在内存,有一个独特的作用域,就是闭包,一般一层 function 调用全局变量不算,而 function 里面定义 function ,这里才会触发闭包。
    solobat
        21
    solobat  
       2017-04-04 19:00:19 +08:00
    看自由变量
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3238 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 39ms · UTC 11:55 · PVG 19:55 · LAX 04:55 · JFK 07:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.