一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。


function books(){var book = '书包里的书本';return function(){console.log(book);}}var bag = books();bag();// 匿名函数执行上下文 = {作用域链: {匿名函数变量对象 + books变量对象 + 全局变量对象}, {变量对象: }}// books执行上下文 = {作用域链: {books变量对象 + 全局变量对象}, {变量对象: book}}// 全局执行上下文 = {作用域链: {全局变量对象}, {变量对象: books, bag}}
for(var i = 0; i < 5; i++){(function(x){console.log(x++);})(i);}console.log(i);// 立即执行函数执行上下文 = {作用域链: {立即执行函数变量对象 + 全局变量对象}, {变量对象: x}}// 全局执行上下文 = {作用域链: {全局变量对象}, {变量对象: i}}
for(var i = 0; i < 5; i++){setTimeout(function(){console.log(i++);});}console.log(i);// 输出为 5 5 6 7 8 9
for(var i = 0; i < 5; i++){(function(x){setTimeout(function(){console.log(x);},4000)})(i)}console.log(i);// 输出为 5 0 1 2 3 4
<!DOCTYPE html><html><script>var b = 'boy';console.log(b);function fighting(){console.log(a);console.log(b);if(a === 'apple'){a = 'Alice';}else{a = 'Ada';}console.log(a);var a = 'Andy';middle();function middle(){console.log(c++);var c = 100;console.log(++c);samall();function samall(){console.log(a);}}var c = a = 88;function bottom(){console.log(this.b);b = 'baby';console.log(b);}bottom();}fighting();console.log(b);</script></html>
