闭包就是在函数内部创建一个函数,内部函数可以访问函数的作用域。闭包会随着函数的创建而创建。
举例说明:
function init() {
  var name = "Mozilla"; // name 是一个被 init 创建的局部变量
  alert('执行的init函数')
  return function() { // 匿名的内部函数,一个闭包
        // 闭包可以访问外部函数的作用域
      alert(name); // 使用了父函数中声明的变量
  }
}
init(); 执行init函数,创建了匿名闭包函数,但是没有执行。
init()();执行init函数,并且执行了匿名闭包函数。
1. forEach与js闭包
function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}
function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];
    
  helpText.forEach(function(item){
    document.getElementById(item.id).onfocus = function(){
      showHelp(item.help)
    }
  })
}
2. for循环与js闭包
function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}
//创建一个单独的词法作用域,
function a(item){
    return function(){
        console.log(item)
        showHelp(item.help)
    }
}
function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];
    
  // onfocus事件会创建一个闭包,使用的同一个词法作用域。	
  for (var i = 0; i < helpText.length; i++) {
    var item = helpText[i];
    document.getElementById(item.id).onfocus = a(item)
  }
}
setupHelp();
3. 定时器与js闭包
function a(i){
  return function(){
    console.log(i)
  }
}
for(var i=0;i<5;i++) {
  var fn = a(i) //每个定时器都创建一个独立的词法作用域
  setTimeout(fn,1000)
}
4. let和const与js闭包
function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}
function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];
  // 使用let或者const定义item之后,item会转换为块级作用域。从而无需使用闭包来实现。
  for (let i = 0; i < helpText.length; i++) {
    let item = helpText[i];
    document.getElementById(item.id).onfocus = function(){
      showHelp(item.help);
    }
  }
}
setupHelp();
function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}
function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];
  // 错误的js闭包。
  /** 
   * 错误原因:循环创建的闭包在同一个词法作用域下。在这个作用域中存在一个变量 item。
   * 这是因为变量 item 使用 var 进行声明,由于变量提升,所以具有函数作用域。
   * 当 onfocus 的回调执行时,item.help 的值被决定。
   * 由于循环在事件触发之前早已执行完毕,变量对象 item(被三个闭包所共享)已经指向了 helpText 的最后一项。
  **/
  for (var i = 0; i < helpText.length; i++) {
    var item = helpText[i];
    console.log(i) // 先遍历了三次。item为helpText最后一个
    document.getElementById(item.id).onfocus = function(){ //回调
      showHelp(item.help)
      console.log("我是onfocus事件执行")
    }
  }
}
setupHelp();
代码已经上传到 https://gitee.com/usuing/lession.git,喜欢可以star一下。
