关于JS的 闭包,想问个问题

  function f1(){
      var result=[];
      for(var i=0;i<10;i++){
          result[i]=function(){
              return i
          }
      }
      return result
  }
  console.log(  f1()[0]()  )  
  console.log(  f1()[1]()  )

结果都是10,我的理解是这样的:
调用f1()[0]()是先执行第一个小括号f1(),此时result[0],result[1]..的值都是一个函数而未赋具体的值,也就是下边这代码并未执行

      return i

,尽管此时的i是0,1,2,3...;f1()执行完后i的值变成了10;而执行到第二个小括号f1()[0]()时,

      return i

这段代码才真正的起作用,但此时i变成了10

问一下我的理解对吗

阅读 2.3k
4 个回答

闭包是一个绑定执行环境的函数,执行环境中i经过for循环变成10了,后面执行函数的时候,读到的值就是10

这其实是个变量作用域的问题。i在f1的最终值是10。var的作用域有两个,一个是全局一个是函数内,而缺少块级作用域,实际代码等同于下面。如果你把var 换成 let那就不一样了。let是有块级作用域的。
`

  function f1(){
      var result=[];
      var i =0;
      for(;i<10;i++){
          result[i]=function(){
              return i
          }
      }
      return result
  }
  console.log(  f1()[0]()  )  
  console.log(  f1()[1]()  )

`

楼上正解,i 是在函数作用域内的一个唯一变量,数组中存入的都是这个 i,所以执行的时候也是最终的 i 值

按照你的例子来整理一下代码每一步的执行过程吧。(我先把你的代码贴上来不然你看的时候来回翻挺麻烦的)

function f1(){
  var result=[];
  for(var i=0;i<10;i++){
      result[i]=function(){
          return i
      }
  }
  return result
}
console.log( f1()[0]() )  
console.log( f1()[1]() )

好,我们先看示例的一开始,声明了一个函数 f1,这个时候函数没有被调用他是不会执行的。
然后到第二步,遇到一个API调用向控制台输出内容,开始执行括号内的内容。

  • f1(): 执行函数f1(),返回一个数组内容

    1. 声明全局变量 result 赋值一个空数组
    2. 声明全局变量 i
    3. 执行 for 循环, i赋值为0,符合循环条件进入循环体
    4. 数组result索引为0的内容赋值为一个匿名函数:function(){ return i }
    5. 完成一次循环,变量i +1 继续进入循环判断...
    6. ...
    7. 变量i累加到10,不符合循环条件,结束循环
    8. 返回变量 result
  • f1()[0]: 通过索引[0]访问返回的数组元素内容
  • f1()[0](): 函数执行(执行返回的索引[0]的元素内的匿名函数(function(){ return i }
  • 控制台内输出闭包内变量i的值 10
    第三步:同第二部重新走一遍。

题外话

  1. 虽然两个console.log的内容是一样的,但是函数是执行两遍的,内容地址也是不同的。
  2. 两个console.log在执行的过程中因为函数一直在被使用,所以是不会被回收的,所以其中的闭包是可以读取到上一级的变量i
如果你觉得我讲的不明白,我提供一个BV号,你自己去B站看吧,BV1YJ411R7ap
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题