循环和闭包

工做中大量的使用javascript,可是却并理解闭包是什么?总感受这门语言有其隐蔽的一面,若是可以掌握将会千米大增。javascript

闭包是基于词法做用域书写代码时产生的天然结果,其实闭包在日常书写的js代码中随处可见。java

当函数能够记住并访问所在的词法做用域时,就产生了闭包,即便函数是在当前词法做用域以外执行闭包

PS:我对其的理解是当一段词法做用域的代码执行以后,js引擎会对其进行回收,以便来提升性能,可是闭包阻止了这种回收,使这段词法做用域依旧处在内存当中,当你调用词法做用域中的局部变量时,依旧存在。函数

下面咱们来看一段代码,清晰地展现了闭包:性能

function foo(){spa

    var a = 2;ip

    function bar(){内存

        console.log(a);作用域

    }回调函数

    return bar;

}

var baz = foo();

baz(); //2  ----这就是闭包的效果

在 foo() 执行后,一般会期待 foo() 的整个内部做用域都被销毁,由于咱们知道引擎有垃圾回收器用来释放再也不使用的内存空间。因为看上去 foo() 的内容不会再被使用,因此很 天然地会考虑对其进行回收。 而闭包的“神奇”之处正是能够阻止这件事情的发生。事实上内部做用域依然存在,所以 没有被回收。

function wait(message) {

    setTimeout( function timer() {

        console.log( message );

    }, 1000 );

}

wait( "Hello, closure!" );

wait(..) 执行 1000 毫秒后,它的内部做用域并不会消失,timer 函数依然保有 wait(..) 做用域的闭包。

要说明闭包,for 循环是最多见的例子。

for (var i=1; i<=5; i++) {

     setTimeout( function timer() { console.log( i );

    }, i*1000 );

}

正常状况下,咱们对这段代码行为的预期是分别输出数字 1~5,每秒一次,每次一个。

但实际上,这段代码在运行时会以每秒一次的频率输出五次 6。

事实上, 当定时器运行时即便每一个迭代中执行的是 setTimeout(.., 0),全部的回调函数依然是在循 环结束后才会被执行,所以会每次输出一个 6 出来。

正确的作法是,咱们要使用闭包,首先按照定义咱们要给每次循环一个词法做用域,每一个做用域都要有本身的i的值,以下:

for(var i =1; i<=5;i++){

    (function(i){ //给每次循环一个独立的词法做用域

        setTimeout(function(){

            console.log(i);

        },i*1000);

    })(i);

}

固然在ES6中,能够用let声明:

for (let i=1; i<=5; i++) {

     setTimeout( function timer() {

        console.log( i );

    }, i*1000 );

}

相关文章
相关标签/搜索