# 闭包练习

# 练习1:

如下代码输出多少?如果想输出3,那如何改造代码?

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

输出10 fnArr[3]() 执行匿名函数 function(){ return i} ,函数内部无i,for循环内部无作用域,匿名函数作用域为全局作用域,for循环执行完毕后i变为10,所以输出i=10

  • 方法1
var fnArr = []
for (var i = 0; i < 10; i ++) {
  fnArr[i] =  (function(j){
    return function(){
      return j
    } 
  })(i)
}
console.log( fnArr[3]() ) // 3

//等价于
  fnArr[3] =  (function(j){
    return function(){
      return j
    } 
  })(3)
//继续简化
var a =  (function fn(j){
    return function(){
      return j
    } 
  })(3)
a()
//相当于a等于立即执行函数,继续简化
function fn(j){
    return function(){
      return j
    } 
var a = fn(3)
//继续
function fn(j){
    function f(){
        return j
    }
    return f
 } 
var a = fn(3)
  • 方法2
var fnArr = []
for (var i = 0; i < 10; i ++) {
  (function(i){
    fnArr[i] =  function(){
      return i
    } 
  })(i)
}
console.log( fnArr[3]() ) // 3
  • 方法3
var fnArr = []
for (let i = 0; i < 10; i ++) {
  fnArr[i] =  function(){
    return i
  } 
}
console.log( fnArr[3]() ) // 3

# 练习2

如下代码输出多少?如何连续输出 0,1,2,3,4

for(var i=0; i<5; i++){
  setTimeout(function(){
    console.log('delayer:' + i )
  }, 0)
}
delayer:5
delayer:5
delayer:5
delayer:5
delayer:5

setTimeout将当前函数加到任务队列,待for循环结束后执行任务队列;当前作用域无i,上级i=5,所以输出5次delayer:5

  • 方法1:
for(var i=0; i<5; i++){
  (function(j){
    setTimeout(function(){
      console.log('delayer:' + j )
    }, 0)    
  })(i)
}

//等价于
function fn(j){
  var j = arguments[0]
  setTimeout(function(){
      console.log('delayer:' + j )
  }, 0) 
}
fn(i)
  • 方法2
for(var i=0; i<5; i++){
  setTimeout((function(j){
    return function(){
      console.log('delayer:' + j )
    }
  }(i)), 0)    
}

# 练习3:

如下代码输出多少?

function makeCounter() {
  var count = 0

  return function() {
    return count++
  };
}

var counter = makeCounter()
var counter2 = makeCounter();

console.log( counter() ) // 0
console.log( counter() ) // 1

console.log( counter2() ) // 0
console.log( counter2() ) // 1

counter与counter2指向不同对象,作用域不同。