javascript中闭包的一些理解
myux8313
8年前
<p>闭包是javascript中绕不开的话题,关于闭包的一些概念和应用,这方面资料比较多,在此就不再赘述。众所周知,闭包的一个作用就是 让一些变量始终保持在内存中 ,在此我用一些实际代码对这句话作进一步的理解。</p> <pre> <code class="language-javascript">demo1: function closure(){ var n = 0; function test() { console.log(++n); } test() test() } a(); //输出1,2(这个很好理解,不多说) demo2:</code></pre> <pre> <code class="language-javascript">function test(){ var i=0; return function(){ console.log(i++); } } var fn = test(); fn(); //输出0 fn(); //输出1</code></pre> <p>上述代码中,fn就是执行函数test()返回的匿名函数。由于fn又是一个全局变量,生命周期一直存在,且这个匿名函数引用了父函数test里面的一个局部变量,所以变量i的状态会被一直保存.</p> <p>demo3:</p> <pre> <code class="language-javascript">function test(){ var i=0; return function(){ console.log(i++); } } test()(); //输出0 test()(); //输出0</code></pre> <p>上述代码中,执行test()返回的是其内部的匿名函数,但是执行完test()()以后,该匿名函数的生命周期已经结束,所以变量i的状态没有得到保存。</p> <p>最近在简书上读到一篇有趣的文章,其中一些代码如下:</p> <pre> <code class="language-javascript">for (var i = 0; i < 5; i++) { setTimeout((function(i) { console.log(i); })(i), i * 1000); } //输出0,1,2,3,4</code></pre> <p>上述代码中有一个setTimeout()函数,其使用格式为setTimeout(func,time),意思是至少过time时间后,执行func。有了这样的认识后,我们可以把func等价成:</p> <p>(function(i){console.log(i)})(i)这个自执行函数。所以这个事情分两步,首先每次循环自执行函数肯定会立即执行一次,会依次输出1,2,3,4。其次,每过time时间,执行一次func,但是在上述代码中,func等价于一个立即执行函数,没有返回值,故什么也不会做。</p> <p>如果把上述代码改成这样:</p> <pre> <code class="language-javascript">for (var i = 0; i < 5; i++) { var j=7; setTimeout((function(i) { console.log(i); return function(){ console.info(j++); } })(i), i * 1000); }</code></pre> <p>上述代码会依次输出0,1,2,3,4, 7,8,9,10,11(结合这个例子理解上一个问题,就容易多了)</p> <p>如果把上面的代码改成这样呢?</p> <pre> <code class="language-javascript">for (var i = 0; i < 5; i++) { setTimeout(function() { console.log(i); }, i * 000); }</code></pre> <p>运行上面的代码会输出5个5(这一点现在可以理解了吧),有人不解的是为什么是每隔一秒输出5而不是隔五秒输出5。setTimeout(func,time)这个函数延迟执行的只是func里面的动作,而time的值是不存在延迟的。上面执行for循环,相当于:setTimeout(func,1000),setTimeout(func,2000) .... 第一次setTimeout执行的时候等了一秒(准确地说,至少要等一秒),第二次setTimeout执行的时候等2秒,但是前面第一次执行的setTimeout函数时,已经等了一秒,所以只需再等一秒就可以立即执行了。在这里,需要弄明白的是,setTimeout函数延迟执行的时间,起点是从time开始赋值的时候计算的,不是从上一个setTimeout函数执行完开始算的。</p> <p> </p> <p>来自:https://segmentfault.com/a/1190000008571702</p> <p> </p>