关于闭包,一个老僧长谈的话题;js的闭包俺将的对照多了,而且很详细,,俺就不说了,可以看看之前的文章;
我们来比拟一下c#中的闭包和js中的闭包;
先看我们的c#代码;
static List<Action> fn0() { int result = 0; List<Action> list = new List<Action>(); for (int i = 0; i < 10; i++) { result = i + 1; //这样result相当于一个全局变量 Action action = () => { Console.WriteLine(result); }; list.Add(action); } return list; } static List<Action> fn1() { List<Action> list = new List<Action>(); for (int i = 0; i < 10; i++) { int result = i + 1; //这样相当于一个局部变量; for 循环内部的变量; Action action = () => { Console.WriteLine(result); }; list.Add(action); } return list; } static void Main(string[] args) { //这样看到了,功效全尼玛的是十滴呀; fn0().ForEach(o=>o()); Console.WriteLine("------------------"); //闭包的问题会在我们的for循环和多线程中呈现id呀;效果不一般滴呀; fn1().ForEach(o => o()); }
功效可想而知;
那么对付,第二种方法,如果我们使用js代码来实现呢;(ps:js的数组可以直接存我们的函数,ps:js中函数就是东西,所以就可以存)
function show(){ var arr=[]; for(var i=0;i<10;i++){ var result=i+1; arr.push(function (){ console.log(result); }) } return arr; }; var list=show();
for(var i=0;i<list.length;i++){
list[i]();
}
功效:
呈现这样的原因很简单啦,俺都不想再反复,因为js中没有块级感化域的观点;不不不不,这样说不太正确,具体的应该是在esx版本前没有,具体的俺也记不清楚了;
解决要领有很多呀;形成闭包啊,使用let 关键字呀;
让我们来看看闭包是如何形成的;
function show(){ var arr=[]; for(var i=0;i<10;i++){ var result=i+1; arr.push(function (index){ return function (){ console.log(index); } }(result)) } return arr; }; var list=show(); for(var i=0;i<list.length;i++){ list[i](); }
它借助了我们的function(最外面的function)形成了一个新的感化域(result=index),这样i=>result=>index就形成了,我们的一个独立的块级别多用于了滴呀;
要领还挺巧妙的,但是对付新的es,一个let就可以解决问题了;
总结:问题的素质:js中没有块级别感化域,通过function形成一个新的额块级别感化域;这样innerfunction 访谒outerfunction的变量(参数);就形成了我们的闭包;
闭包的界说之一:这里我强调的是界说之一://函数内部可以访谒函数地址的感化域;,固然它有一个明显的问题就是:内存泄漏;
再回过头来看看我们c#中代码,以为c#中是有块级别感化域的,所以,要领二就没有问题;
我们看看;*上界说:
闭包:词法闭包;是引用了*变量的函数;这个被引用的*变量,和这个函数一同存在,便是已经分开了缔造它的环境;所以。有另一种说法认为:
闭包是由函数和与其相关的引用环境组合成的实体;
var x = 1; Action action = () => { var y = 2; var result = x + y; Console.Out.WriteLine("result = {0}", result); }; action();
当你在代码调试器(debugger)里不雅察看“action”时,会发明很有趣的工作。我们可以看到,C# 编译器为我们创建了一个 Target 类,里面封装了 x 变量:
如最上面的栗子中,我们在fn0(for中界说第一个的result),以外的处所挪用它是,变量依然是存在的;这个就是我们闭包生气的处所;
何制止闭包陷阱呢?C#中遍及的做法是,将匿名函数引用的变量用一个姑且变量生存下来,然后在匿名函数中使用姑且变量
我们再来看一段经典的js代码: