直接上案例,是摘自《javascript面向对象编程》中的一个案例。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <h1 id="h1"> 这里一共创建了3个闭包,他们都指向了一个共同的局部变量i。但是闭包并不会记录他们(变量i)的值,他们(变量i)所拥有的只是一个一个i的链接(即引用),因此只能返回i的当前值。由于循环结束时i=3,所以这三个函数都指向了这一共同值。 </h1> </body> <script> function f1() { var a = []; var i; for(i=0;i<3;i++) { a[i] = function () { return i; } } return a; } var a = f1(); console.log(a[0]());// 3 console.log(a[1]());// 3 console.log(a[2]());// 3 // 解决办法1: // 不直接创建一个返回i的函数,二十将i传递给一个自调函数。 // 在该函数中,i 就被赋值给了一个局部变量x,这样一来,每次迭代中的x就会拥有各自不同的值了 // 实现的关键,是在中间函数内,将i的值“本地化”,存储到本地,中间函数的参数也是本地化数据 // 下面函数f2最终 return 的是x,x 是函数b[i]的形参,形参是存储b[i]作用域的,当被传入实参i的时候,x分别是1,2,3,return 的也是传入的实参 1,2,3,只要将 i 的值传入函数b[i],i 与函数 f2的 返回值就没有直接关联了。 function f2() { var b= []; var i; for(i= 0;i<3;i++) { b[i] = (function(x){ return function() { return x } })(i) } return b; } var b = f2(); console.log(b[0]());// 0 console.log(b[1]());// 1 console.log(b[2]());// 2 // 不使用自调函数的写法 function f3() { var b= []; var i; var mkClosure = function (x) { return function () { return x; } } for(i=0;i<3;i++) { b[i] = mkClosure(i) } return b; } var c = f3(); console.log(c[0]());// 0 console.log(c[1]());// 1 console.log(c[2]());// 2 </script> </html>