欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

javascript的闭包和变量

程序员文章站 2022-04-27 14:37:36
...

for(var i=0;i<10;i++) {
setTimeout(function() {
console.log(i);
}, 300);
}
运 行它可以发现,连续输出了10个10.为什么呢?因为 “i” 这个变量在内存里只保存了一份。当调用settimeout方法时,往js事件线程的等待队列排入了十个执行函数,一直到每个300ms结束,这十个执行 函数才被调用,此时内存里的 “i” 这个变量经过十次循环最终值已变成了10 。所以就输出了10个10了。那怎么样输出0-9呢?我们可以用闭包把代码稍微改造下:
for(var i=0;i<10;i++) {
setTimeout((function(j) {
return function() {
console.log(j);
}
})(i), 300);
}
此 时就会输出我们想要的结果了,为什么?因为我们在给settimeout传参前,先使用闭包重新生成了一个执行函数,并且把当时循环里的"i"的值作为参 数传入到闭包函数中,结果函数无论什么时候执行,都打出的是当时被传入的那个值。由此说明:在给函数传参时,如果传入的参数是位于栈内存上的时候,会将栈 内存值复制一份传入到函数中。
那如果所传参数是个对象,也就是存在于堆内存上时会怎么办,我们接着做一个实验,这次的循环对象是一个对象字面量:
var obj = {j:0};
for(var i=0;i<10;i++) {
obj.j++;
setTimeout((function(o) {
return function() {
console.log(o.j);
}
})(obj), 300);
}
输出了什么?还是10个10!为什么?虽然还是使用闭包将当前循环的对象状态作为参数传入执行函数中,但传入的只是栈内存上的变量指针,位于堆内存上的内存仍然只有一份,所以这10个等待任务最终开始执行时,输出的都是同一份内存值。
由此我们得出几个最终结论:
1、对于基础数据类型,函数传参的时候会将变量值复制一份传入到函数中。
2、对于对象数据类型,函数传参时是将变量的指针复制一份,真正的变量值只有一份。
由于变量指针和基础类型变量都位于栈内存上,所以传参就是将栈内存复制一遍,堆内存不变。