描述如题
代码如下
function test() {
for(var i=0; i<10; i++) {
setTimeout(function(){
(function (m) {
console.log(m);
})(i)
}, 500)
}
}
test();
function test() {
for(var i=0; i<10; i++) {
setTimeout(function(){
(function (m) {
console.log(m);
})(i)
}, 500)
}
}
test();
题主之所以会出现此问题,完全是由于没有理解闭包
es5之前js是没有块级作用域这个说法的
可以通过()()来模拟块级作用域
for(var i = 0; i < 10; i++) {
setTimeout((function(){
console.log(i)
})(),500)
}
// 0 1 2 3 4 5 6 7 8 9
es6通过let命令,声明变量只在书写的let命令代码块内有效
所以 @radius 写的就复杂了
for(let i=0; i<10; i++) {
setTimeout(function(){
console.log(i);
}, 500)
}
// 0 1 2 3 4 5 6 7 8 9
es2016 or typescript:
async function test() {
var i = 0;
for (i = 0; i < 10; i++) {
await new Promise(resolve => setTimeout(resolve, 500));
console.log(i);
}
}
test();
function test() {
for(var i=0; i<10; i++) {
(function(i){
setTimeout(function(){
console.log(i);
},500);
})(i)
}
}
test();
这个是循环0-9 1-10你自己改
function test() {
for(var i = 1 ;i<=10;i++){
(function(i){
setTimeout(function(){
console.log(i)
},500)
})(i);
}
}
test();
function test(){
for(var i = 0 ;i<10 ;i++){
setTimeout((function(m){
return function(){ console.log(m)}
})(i),500);
}
}
test();
function test() {
for(var i=1; i<=10; i++) {
setTimeout((function(m){
return function () {
console.log(m);
}
})(i), 500 * i)
}
}
test();
function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push(function () {
return i * i;
});
}
return arr;
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
在上面的例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都添加到一个Array中返回了。
你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果是:
f1(); // 16
f2(); // 16
f3(); // 16
返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
廖雪峰教程:闭包
function test() {
for(let i=0; i<10; i++) {
setTimeout(function(){
(function (m) {
console.log(m);
})(i)
}, 500)
}
}
test();
只把var改成let就行了
错的原因是对JS变量提升的概念理解不透彻
function test() {
for(var i=0; i<10; i++) {
setTimeout(function(){
(function (m) {
console.log(m);
})(i)
}, 500)
}
}
test();
换成let就好,每次循环都创建一个块级作用域
用递归来代替循环
function delayLoop(factory, time, count, _i = 0, _timer = []) {
if(_i >= count) return _timer
var timer = setTimeout(() => {
_timer[_i] = undefined
factory(_i)
_i ++
delay(factory, time, count, _i, _timer)
}, time)
_timer.push(timer)
return _timer
}
// usage
var count = 10
var interval = 1000
var timer = delayLoop((i) => {
console.log(i)
}, interval, count)
// stop
setTimeout(() => timer.filter(item => !!item).forEach(t => clearTimeout(t)), 3200)
for(let i = 0; i < 10; i++) {
setTimeout(function(){
console.log(i)
},500)
}
最好的办法就是直接用let
就好了
而下边这种写法
function test() {
for(var i=1; i<11; i++) {
setTimeout((function(){
console.log(i);
})(), 500)
}
}
相当于
function test() {
for(var i=1; i<11; i++) {
setTimeout(console.log(i), 500)
}
}
是不会有延时的。
除非:
function test() {
for(var i=1; i<11; i++) {
setTimeout((function(i){
return function() {
console.log(i);
}
})(i), 500)
}
}
明白了了吧,但是还是用let
吧,骚年!
8 回答4.8k 阅读✓ 已解决
6 回答3.5k 阅读✓ 已解决
5 回答2.9k 阅读✓ 已解决
5 回答6.4k 阅读✓ 已解决
4 回答2.3k 阅读✓ 已解决
4 回答2.8k 阅读✓ 已解决
3 回答2.5k 阅读✓ 已解决
直接在
setTimeout()
里用即时执行封装下回调就行了,你封包在setTimeout()
的里边跟没封区别不大:补充:
如果想做成间隔500ms一次console.log,那我觉得不如直接写成: