如何理解闭包

1.使用var:

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

2.使用let

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6

问题:在1中,循环内被赋给数组a的函数内部的console.log(i),里面的i指向的是全局的i,那a[i]的i岂不是也指向全局的i,那岂不是只有a[10]有值?

阅读 4.2k
7 个回答

1、循环中的语句是立即执行
2、每进一次循环,都会给数组第i项赋值
3、这里赋值的是个函数,但函数并没有执行
所以循环完了是这样的:

[
function(){console.log(i)},
function(){console.log(i)},
function(){console.log(i)},
function(){console.log(i)},
function(){console.log(i)},
function(){console.log(i)},
function(){console.log(i)}
]
//由于全局的i是10
//所以每一项打印都是10

这个题还是不要扯到闭包上。应该理解var与let的作用域的问题。
看下面的例子,你就知道了。

(function() {
  var varTest = 'test var OK.';
  let letTest = 'test let OK.';

  {
    var varTest = 'varTest changed.';
    let letTest = 'letTest changed.';
  }

  console.log(varTest); //varTest changed.
  console.log(letTest); //test let OK.
}());

再给你一个闭包的例子:

function a(){
  var n = 0;
  function inc() {
    n++;
    console.log(n);
  }
  inc();
  inc();
}
a(); //控制台输出1,再输出2

谢邀。

额……你学拧巴了!

a[i]是一个立即取值,并不适用于闭包的概念。闭包是指一个函数在定义以后,被放到其他环境去执行的情况。此时它的执行环境仍然是定义它的那个环境,而不是执行它的那个环境。

所以闭包是针对调用环境与执行环境不同的函数来说的。其他情况可不能随便套用。

for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}

这里的a[i] 的意思相当于循环给a数组添加十个匿名函数function () {console.log(i);}; 你可以打印一下a你就知道了 a[i]是已经确立的了 至于执行a[6]相当于执行数组中的第7个匿名函数 打印i 这时候因为使用的是var 并不会产生块作用域 所以i的取值等于最外层循环结束的i值就是10

不要为了学闭包而闭包, 考虑闭包能做什么... 我感觉
首先,不要相当然的认为 程序按你的想法运行, 我感觉 计算机 算是一门严谨的科学。
js 词法作用域...
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = (function (i) {

       return function () {
            console.log(i);
          };

})(i)
}
a[6](); // 6

//

我从《你不了解的JS》总结了关于如何理解闭包:

  1. 某个函数拥有上级(或上多级)作用域的引用, 就叫做闭包
  2. 当函数记住并访问其所在的词法作用域, 即便它是在当前词法作用域之外执行, 这就产生了闭包
  3. 闭包可以使得函数就访问定义时的词法作用域, 所以实际上,只要使用了回调函数就使用了闭包

配合一段经典的面试代码就很好理解其一:

function Timer () {
    let time = 1
    return function () {
        console.log(time ++)
    }
}

关于题主的问题,相关闭包,但主要不在“闭包”上,应该是“var与let的作用域的问题”,只有当你了解了闭包并且了解了var与let作用域的不同才能想通这两个循环。

总结下JS的块级作用域(伪块级作用域):

  1. let
  2. try catch
  3. IIFE
  4. with(不推荐使用)
  5. 还有不。。记不清了

支持楼上的看法,学闭包首先得理解这东西到底有什么用,说白了就是保存状态。给你看个闭包实现复合数据结构的例子把,源自SICP 原版是lisp写的

// 闭包实现序对

let cons = (car,cdr) => (k)=> k === 1 ? car : cdr
let car = (cons) => cons(1)
let cdr = (cons) => cons(2)

// 建立一个序对链
var cons2 = cons('序对2', '结束')
var cons1 = cons('序对1', cons2)

console.log(cdr(cdr(cons1))) // 结束
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题