function
fn() {
for
(
var
i=0 ; i<2; i++) {
//(function(){
var
backup = i;
setTimeout(
function
() {
alert(backup);
}, 2000);
//})();
}
}
fn();
function
fn() {
for
(
var
i=0 ; i<2; i++) {
(function(){
var
backup = i;
setTimeout(
function
() {
alert(backup);
}, 2000);
})();
}
}
fn();
简单一句话说就是Javascript中的函数调用也是通过堆栈实现的,所以你最后例子就变成:
function fn() { for(var i=0 ; i<2; i++) { (function(){ ---> var backup = i; setTimeout(function() { | ==> 单独看成一个函数FNN() alert(backup); }, 2000); })(); ---> alert("a"); } }
然后就变成了这样:
function fn() { for(var i=0 ; i<2; i++) { FNN() alert("a"); } }
接着js引擎执行就变成这样了:
首先是fn函数压堆栈,接着在内部碰上了FNN,那么再将FNN压堆栈,然后执行就变成这样了:
fn先执行完然后才能调用FNN,所以就造成了先alert(a)然后才是弹出FNN内部执行的结果了. 至于弹出为什么先弹出1后是0,我这边是没有这种情况的,正常输出0,1google浏览器~
ps: 不要让setTimeout的表象给欺骗了
需要说明下以上回答只针对你的例子,在setTimeOut调用情况下,所以不要误解成所以类似情况下(不存在settimeout)都是这样子,那就错了
我的也是Chrome浏览器就是1和0,主要就是这里不懂?
还有就是闭包之后会正常弹出0和1是因为闭包的时候把var i=0和var i=1当成了两个对象地址去存储了么?
@﹏℡幸福?:
i是基本类型不是对象,所以存储上跟对象是有点区别的,如果按存储方式来分是在栈上的.
针对2,3例子说明:
1. 闭包后输出为0,1的情况
闭包后其实相当于(function(){})处的代码是独立函数了,backup =i 赋值也是马上在该函数上下文中生效的,所以alert后输出0,1结果是很正常的
2. 不闭包情况下,你说输出0,1情况,其实我有点奇怪,如果按我的理解应该是输出1,1才对的,因为在第一次执行i=1时候上次运行的backup = 0情况下backup已经被销毁了,而等到settimeout执行时间到时候backup应该是等于1的,所以两次应该都是1才对,除非settimeout执行的时间小于for的循环
@visonme: 闭包输出0,1是因为都各种保存的backup值,所以两次执行settimeout不会干扰,但是非闭包情况下存在存在首次backup变量被“销毁”的情况,所以应该两次执行settimeout时候输出都为1,1
@visonme:
1.我一直也把内层函数当成独立函数,只不过是引用了外层函数的变量而已。引用您“***闭包后其实相当于(function(){})处的代码是独立函数了,backup =i 赋值也是马上在该函数上下文中生效的,所以alert后输出0,1结果是很正常的***”的这句话,很多人说闭包函数马上生效。我可以证明外层函数是先执行的因为有我闭包alert("a")的代码在,是先弹出了两个alert("a"),才执行内层函数的,意思就是外层函数走完弹出两次alert之间并没有立即执行内层函数。我的外层首先走完了,backup最终只有一个值,如果没有分开记录的话i的话,内层函数怎么会记录两个值呢(虽然先弹的是1,后弹的是0)?
2.不闭包的情况是输出1和1没错。可是我在闭包的情况下加了alert("a");之后先输出1后输出了0,这个加了alert("a")和不加是反着的,为什么呢?
@﹏℡幸福?:
这其实就回到了开始回答了 “Javascript中的函数调用也是通过堆栈实现的”
像你说的闭包函数直接执行是没有错的,但是因为你例子中用的setTimeout,setTIMEout是用于延迟执行某个函数的,所以这里在fn就变成了,alert(a) 先入栈然后才是alert(backup)入栈(在没有settimeout情况下是反过来的)
至于2,先输出1,后 0,这个我就不清楚了,因为我没有出现你这情况正常也不应该是1,0,你只能在查找写资料看看了
@visonme: 所以1中问题因为入栈的先后会出现先执行alert(a)后执行alert(backup)的情况
@visonme:
要注意函数只有在执行的时候才会进行入栈操作,setTimeout的延迟操作才导致了alert(backup)比alert(a)晚入了
@visonme: 嗯,首先谢谢您费心回答我问题了,可就是因为有setTimeout的延迟操作造成了alert(backup)比alert(a)晚入栈,所以内层函数没有立即执行,怎么还会记录两个值呢?我可以理解为外层和变量先入栈,这时栈里只有一个backup=1的值,之后内层函数alert(backup)才入栈么?那它既然晚入栈了怎么又会记录两个值呢?
@﹏℡幸福?:
function cb( i ) { var backup = i ; //因为是独立函数内部,所以自然保存有自己的backup值得 setTimeout( function(){ alert(backup) }, 2000 ); } for( var i = 0 ; i < 2 ; i++ ) { (function(){ cb( i ); })(); } //backup是cb函数中定义的局部变量,当你将i传给cb时候,cb函数就保存了一份i的值 //并将这个值存储在局部变量backup里面了 //如果是下面就不同了 for( var i = 0 ; i < 2 ; i++ ) { //(function(){ var backup = i ; setTimeout(function(){ alert(backup); },2000); //})(); } //这种情况就不一样了,因为setTimeout延迟执行的特性,导致最后在执行alert时候取了最后赋值的backup了 //其实在i = 0 时候 backup = 0 //但是当i = 1 时候,上次定义的backup已经没有意义了,因为这里重新定义了一个backup
其实刚开始对一些概念不理解的地方不需要一直咬着不放的,先一笔带过,等以后接触的知识多了,项目做多了,一些概念自然就回明白了
很多知识点在开始前都是这样模糊的,等后面自己知识面广了,一些以前的疑惑就会自然解除了
@visonme: 非常感谢!
function fn() { for(var i=0 ; i<2; i++) { (function(){ var backup = i; setTimeout(function() { alert(backup); }, 2000); })(); alert("a"); } } fn();
千万不要晕,也不能晕。
1、这是一个函数闭包
2、js是单线程的
3、setTimeout会是一个异步的操作,不管时间多长也是异步,既然是异步,线程并不会等待(知道遇到alert等),会事先把两个alert('a')入栈,之后function(){alert(backup)}才会入栈,所有会出现先执行两次‘a’,再执行1,2的效果