Daily-Interview-Question icon indicating copy to clipboard operation
Daily-Interview-Question copied to clipboard

第 31 题:改造下面的代码,使之输出0 - 9,写出你能想到的所有解法。

Open zpzxgcr opened this issue 5 years ago • 66 comments

for (var i = 0; i< 10; i++){
   setTimeout((i) => {
	console.log(i);
   }, 1000,i)
}

zpzxgcr avatar Mar 12 '19 00:03 zpzxgcr

// 解法一:
for (let i = 0; i< 10; i++){
  setTimeout(() => {
    console.log(i);
  }, 1000)
}
// 解法二:
for (var i = 0; i< 10; i++){
  ((i) => {
    setTimeout(() => {
      console.log(i);
    }, 1000)
 })(i)
}

jefferyE avatar Mar 12 '19 00:03 jefferyE

for (var i = 0; i< 10; i++){
  setTimeout(((i) => {
	console.log(i);
    })(i), 1000)
}

for (var i = 0; i< 10; i++){
   setTimeout((() => {
	console.log(i);
    })(), 1000)
}


for (let i = 0; i< 10; i++){
    setTimeout(() => {
	console.log(i);
    }, 1000)
}


gaomin avatar Mar 12 '19 01:03 gaomin

正常写法:

for (var i = 0; i < 10; i++) {
    setTimeout(((i) => {
        console.log(i);
    })(i), 1000)
}

砸场子写法:

let i = 0,
timer = setInterval(() => {
    i < 10 ?
    console.log(i++) :
    clearInterval(timer);
})

MarsGT avatar Mar 12 '19 05:03 MarsGT

 for(let i = 0 ; i < 10; i++){
            setTimeout(()=>{
                console.log(i)
            },1000)
        }
for(var i = 0 ; i < 10 ; i++){
          (function(i){
              setTimeout(()=>{
                  console.log(i)
              },1000)
          }(i))
      }    

yuejuanmyword avatar Mar 12 '19 06:03 yuejuanmyword

解决办法汇总

  • 方法一

    原理:

    • 利用 setTimeout 函数的第三个参数,会作为回调函数的第一个参数传入
    • 利用 bind 函数部分执行的特性

    代码 1:

    for (var i = 0; i < 10; i++) {
      setTimeout(i => {
        console.log(i);
      }, 1000, i)
    }
    

    代码 2:

    for (var i = 0; i < 10; i++) {
      setTimeout(console.log, 1000, i)
    }
    

    代码 3:

    for (var i = 0; i < 10; i++) {
      setTimeout(console.log.bind(Object.create(null), i), 1000)
    }
    
  • 方法二

    原理:

    • 利用 let 变量的特性 — 在每一次 for 循环的过程中,let 声明的变量会在当前的块级作用域里面(for 循环的 body 体,也即两个花括号之间的内容区域)创建一个文法环境(Lexical Environment),该环境里面包括了当前 for 循环过程中的 i具体链接

    代码 1:

    for (let i = 0; i < 10; i++) {
      setTimeout(() => {
        console.log(i);
      }, 1000)
    }
    

    等价于

    for (let i = 0; i < 10; i++) {
      let _i = i;// const _i = i;
      setTimeout(() => {
        console.log(_i);
      }, 1000)
    }
    
  • 方法三

    原理:

    代码 1:

    for (var i = 0; i < 10; i++) {
      (i => {
        setTimeout(() => {
          console.log(i);
        }, 1000)
      })(i)
    }
    

    代码 2:

    for (var i = 0; i < 10; i++) {
      try {
        throw new Error(i);
      } catch ({
        message: i
      }) {
        setTimeout(() => {
          console.log(i);
        }, 1000)
      }
    }
    
  • 方法四

    原理:

    • 很多其它的方案只是把 console.log(i) 放到一个函数里面,因为 setTimeout 函数的第一个参数只接受函数以及字符串,如果是 js 语句的话,js 引擎应该会自动在该语句外面包裹一层函数

    代码 1:

    for (var i = 0; i < 10; i++) {
      setTimeout(console.log(i), 1000)
    }
    

    代码 2:

    for (var i = 0; i < 10; i++) {
      setTimeout((() => {
        console.log(i);
      })(), 1000)
    }
    

    代码 3:

    for (var i = 0; i < 10; i++) {
      setTimeout((i => {
        console.log(i);
      })(i), 1000)
    }
    

    代码 4:

    for (var i = 0; i < 10; i++) {
      setTimeout((i => {
        console.log(i);
      }).call(Object.create(null), i), 1000)
    }
    

    代码 5:

    for (var i = 0; i < 10; i++) {
      setTimeout((i => {
        console.log(i);
      }).apply(Object.create(null), [i]), 1000)
    }
    

    代码 6:

    for (var i = 0; i < 10; i++) {
      setTimeout((i => {
        console.log(i);
      }).apply(Object.create(null), { length: 1, '0': i }), 1000)
    }
    
  • 方法五

    原理:

    • 利用 eval 或者 new Function 执行字符串,然后执行过程同方法四

    代码 1:

    for (var i = 0; i < 10; i++) {
      setTimeout(eval('console.log(i)'), 1000)
    }
    

    代码 2:

    for (var i = 0; i < 10; i++) {
      setTimeout(new Function('i', 'console.log(i)')(i), 1000)
    }
    

    代码 3:

    for (var i = 0; i < 10; i++) {
      setTimeout(new Function('console.log(i)')(), 1000)
    }
    

ghost avatar Mar 12 '19 11:03 ghost

利用try/catch的块级作用域也能实现目的:

for(var i = 0; i < 10; i++){ 
  try{
     throw i;
  }catch(i){
     setTimeout(() => { console.log(i); },1000)    
  }
}       

btea avatar Mar 12 '19 14:03 btea

闭包解法

setTimeout(() => {
	for (var i = 0; i< 10; i++){
	console.log(i);}
    }, 1000);

jerrychane avatar Mar 12 '19 15:03 jerrychane

for (var i = 0; i< 10; i++){
   setTimeout((i) => {
   console.log(i);
   }, 1000,i)
}

除了 let 这个可能是改动最少的😂

oliyg avatar Mar 12 '19 15:03 oliyg

for (var i = 0; i< 10; i++){
    (() => {
        var temp = i // 闭包
        setTimeout(() => {
            console.log(temp);
        }, 1000)
    })()
}

oliyg avatar Mar 12 '19 15:03 oliyg

利用try/catch的块级作用域也能实现目的:

for(var i = 0; i < 10; i++){ 
  try{
     throw i;
  }catch(i){
     setTimeout(() => { console.log(i); },1000)    
  }
}       

涨知识啦

gaomin avatar Mar 13 '19 01:03 gaomin

for(let i=0;i<10;i++){ setTimeout(() => { console.log(i); }, 1000); }

for(var i=0;i<10;i++){ ( function(){ var j = i; setTimeout((()=>{ console.log(j) }),1000) } )() }

for(var i=0;i<10;i++){ (function(i){ setTimeout((()=>{ console.log(i) }),1000) })(i) }

SDXYRR avatar Mar 13 '19 03:03 SDXYRR

for (var i = 0; i< 10; i++){
   setTimeout(((i) => {
   console.log(i);
   }).call(null,i), 1000)
}

GitHdu avatar Mar 13 '19 11:03 GitHdu

最简单的将var改成let

for (let i = 0; i< 10; i++){
   setTimeout(() => {
   console.log(i);
   }, 1000)
}

chenchangyuan avatar Mar 16 '19 04:03 chenchangyuan

其实有些方法是不满足要求的,为啥这样说呢?因为题目其实是有隐性要求,也即每隔 1s 输出一个数字,虽说题目没有明确说出来。所以这种解法不满足要求,比如:

for (var i = 0; i < 10; i++) {
  setTimeout(console.log(i, Date.now()), 1000)
}

ghost avatar Mar 16 '19 11:03 ghost

for (let i = 0; i< 10; i++){ setTimeout(() => { console.log(i); }, 1000) } for (var i = 0; i< 10; i++){ (function(i){ setTimeout(() => { console.log(i); }, 1000) })(i) }

hmmoshang avatar Mar 28 '19 05:03 hmmoshang

for (var i = 0; i < 10; i++) { console.log(i) }

asd8855 avatar Apr 12 '19 07:04 asd8855

  // 1 使用es5 块级作用域 let
  for (let i = 0; i< 10; i++){
    setTimeout(() => {
      console.log(i);
    }, 1000)
  }

  // 2 闭包法
  for (var i = 0; i< 10; i++){
    (function(i) {
      setTimeout(() => {
        console.log(i);
      }, 1000)
    })(i)
  }


  // 3 promise
  for (var i = 0; i< 10; i++){
    new Promise((r,ej) => ej(i)).catch(i => setTimeout(() => {
          console.log(i);
      }, 1000))
  }


  // 4 let 临时变量
  for (var i = 0; i< 10; i++){
    let _i = i;
    setTimeout(() => {
      console.log(_i);
    }, 1000)
  }

  // 5 setTimeout传参
  for (var i = 0; i< 10; i++){
    setTimeout(i => {
      console.log(i);
    }, 1000, i)
  }

  // 6 try catch法
  for (var i = 0; i< 10; i++){
    try {
      throw i;
    } catch (i) {
      setTimeout(() => {
        console.log(i);
      }, 1000)
    }
  }

Caitingwei avatar Apr 19 '19 09:04 Caitingwei

// 解法1 利用setTimeout的第三个参数
 for (var i = 0; i < 10; i++) {
    setTimeout( function timer(param){
        console.log(param);
    },1000, i);
}

// 解法2 用立即执行函数和闭包构建一个单独作用域
for (var i = 0; i < 10; i++) {
    (function(i){
      setTimeout( function (){
        console.log(i);
      },1000);
    })(i);
}

// 解法3 利用let构造块级作用域
for (let i = 0; i < 10; i++) {
    setTimeout( function (){
        console.log(i);
    },1000);
}

// 解法4 利用promise包装setTimeout
for (var i = 0; i < 10; i++) {
    timeoutPromise(i);
}
function timeoutPromise(i) {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log(i);
            resolve(true);
        }, 1000);
    });
}

// 解法5 用generator函数
for (var i = 0; i < 10; i++) {
    timeoutGenerator(i).next();
}
function* timeoutGenerator (i) {
    yield setTimeout(() => {
        console.log(i);
    }, 1000);
}

// 解法6 await async
async function init () {
    for (var i = 0; i < 10; i++) {
        await timeoutPromise(i);
    }    
}
function timeoutPromise (i) {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log(i);
            resolve(true);
        }, 1000);   
    });
}
init();

// 原题
for (var i = 0; i < 10; i++) {
    setTimeout( function (){
        console.log(i);
    },1000);
}

liyixun avatar Jun 01 '19 14:06 liyixun

for(var i = 0; i < 10; i++){ (function(){ console.log(i) })() }

thinkfish avatar Jun 19 '19 07:06 thinkfish

console.log(0),console.log(1),console.log(2),console.log(3),console.log(4),console.log(5),console.log(6),console.log(7),console.log(8),console.log(9)

goodjs111 avatar Jul 09 '19 07:07 goodjs111

for (var i = 0; i< 10; i++){ console.log(i); } 没有人这么写吗?不要打我啊

chphaeton avatar Jul 10 '19 02:07 chphaeton

for (let i = 0; i< 10; i++){ console.log(i); }

又没说一定要用setTimeOut,这难道不是最简单效率最高的一种解法?

lwmxiaobei avatar Jul 10 '19 08:07 lwmxiaobei

1、闭包实现 变量保存,settimeout第三个参数转为函数参数也属于闭包。 2、let创建作用域,实现类似闭包的效果,变量保存 总结,学好闭包就可以了,作用域解决一切花里胡哨

Hunterang avatar Jul 13 '19 07:07 Hunterang

for (var i = 0; i< 10; i++){
   setTimeout((i) => {
   console.log(i);
   }, 1000,i)
}

除了 let 这个可能是改动最少的

这两种解法,都好牛B

chenming142 avatar Jul 16 '19 10:07 chenming142

看到最后没有看到有人写一秒输出一个的情况。 一秒输出一个数字只需要在定时器后面乘以i即可, setTimeout第一个参数是立即执行的函数除外。

zhoushoujian avatar Jul 16 '19 10:07 zhoushoujian

方法1:立即执行函数表达式法简称(IIFE)不标准叫法立即执行函数

for (var i = 0; i<10; i++) {
     // IIFE: (function (j) {})(i);  
     (function (j) {
         setTimeout(function () {
            console.log(j)
         }, 1000)
      })(i)
}

方法2:将var 改为 let

for (let i = 0; i<10; i++) {
    setTimeout(function () {
         console.log(i)
    }, 1000)
}

方法3:使用promise函数

for (var i = 0; i<10; i++) {
   new Promise(function (resolve, reject) {
         resolve(i)
   }).then(function (data) {
        setTimeout(() => {
           console.log(data)
      }, 1000)
  })
}

方法4:使用bind绑定(参考楼上的,加深印象)

for(var i = 0; i<10; i++) {
     setTimeout(console.log.bind(null, i), 1000)
}

方法5: 使用try catch构成块级作用域(参考楼上的,加深印象)

for (var i = 0; i<10; i++) {
    try{
        throw(i)
    }catch (i) {
       setTimeout(function () { 
          console.log(i)
        },1000)
    }
}

另附promise相关的题目

mongonice avatar Jul 23 '19 04:07 mongonice

    for (var i = 0; i< 10; i++){
        setTimeout((i) => {
            console.log(i);
        }, 1000, i)
    }

HuangYongXuan avatar Jul 24 '19 06:07 HuangYongXuan

利用const/let的块级作用域

for (var i = 0; i< 10; i++){
    {
        const j=i;
        setTimeout(() => {
            console.log(j);
        }, 1000)
    }
}

下面这个比较奇葩,看到大佬的cath语句块延长作用域链,就想到了with。

for (var i = 0; i< 10; i++){
    with(new Number(i)){
        setTimeout(() => {
            console.log(valueOf());
        }, 1000)
    }
}

cheny-github avatar Aug 04 '19 07:08 cheny-github

压根就不需要改

1921622004 avatar Aug 07 '19 16:08 1921622004

压根就不需要改

不改i一直++,打印出10.。。你自己试试

GrootWanggg avatar Aug 19 '19 08:08 GrootWanggg

// 闭包
for (var i = 0; i < 10; i++) {
	(function (i){
		setTimeout(() => {
			console.log(i);
		}, 1000);
	})(i);
}

// 块作用域
for (let i = 0; i < 10; i++) {
	setTimeout(() => {
		console.log(i);
	}, 1000);
}

// timeout 传参
for (var i = 0; i < 10; i++) {
	setTimeout((i) => {
		console.log(i);
	}, 1000, i);
}

XJawher avatar Aug 22 '19 01:08 XJawher

题目的意思应该是打印出0-9,并且使每隔1S打印出一个吧。不然setTimeout的意义在哪。直接for(var i=0;i<10;i++)(console.log(i))好了。所以每一个方法上都应该把定时器的时间 *i 吧

解决办法汇总

  • 方法一 原理:

    • 利用 setTimeout 函数的第三个参数,会作为回调函数的第一个参数传入
    • 利用 bind 函数部分执行的特性

    代码 1:

    for (var i = 0; i < 10; i++) {
      setTimeout(i => {
        console.log(i);
      }, 1000, i)
    }
    

    代码 2:

    for (var i = 0; i < 10; i++) {
      setTimeout(console.log, 1000, i)
    }
    

    代码 3:

    for (var i = 0; i < 10; i++) {
      setTimeout(console.log.bind(Object.create(null), i), 1000)
    }
    
  • 方法二 原理:

    • 利用 let 变量的特性 — 在每一次 for 循环的过程中,let 声明的变量会在当前的块级作用域里面(for 循环的 body 体,也即两个花括号之间的内容区域)创建一个文法环境(Lexical Environment),该环境里面包括了当前 for 循环过程中的 i具体链接

    代码 1:

    for (let i = 0; i < 10; i++) {
      setTimeout(() => {
        console.log(i);
      }, 1000)
    }
    

    等价于

    for (let i = 0; i < 10; i++) {
      let _i = i;// const _i = i;
      setTimeout(() => {
        console.log(_i);
      }, 1000)
    }
    
  • 方法三 原理:

    代码 1:

    for (var i = 0; i < 10; i++) {
      (i => {
        setTimeout(() => {
          console.log(i);
        }, 1000)
      })(i)
    }
    

    代码 2:

    for (var i = 0; i < 10; i++) {
      try {
        throw new Error(i);
      } catch ({
        message: i
      }) {
        setTimeout(() => {
          console.log(i);
        }, 1000)
      }
    }
    
  • 方法四 原理:

    • 很多其它的方案只是把 console.log(i) 放到一个函数里面,因为 setTimeout 函数的第一个参数只接受函数以及字符串,如果是 js 语句的话,js 引擎应该会自动在该语句外面包裹一层函数

    代码 1:

    for (var i = 0; i < 10; i++) {
      setTimeout(console.log(i), 1000)
    }
    

    代码 2:

    for (var i = 0; i < 10; i++) {
      setTimeout((() => {
        console.log(i);
      })(), 1000)
    }
    

    代码 3:

    for (var i = 0; i < 10; i++) {
      setTimeout((i => {
        console.log(i);
      })(i), 1000)
    }
    

    代码 4:

    for (var i = 0; i < 10; i++) {
      setTimeout((i => {
        console.log(i);
      }).call(Object.create(null), i), 1000)
    }
    

    代码 5:

    for (var i = 0; i < 10; i++) {
      setTimeout((i => {
        console.log(i);
      }).apply(Object.create(null), [i]), 1000)
    }
    

    代码 6:

    for (var i = 0; i < 10; i++) {
      setTimeout((i => {
        console.log(i);
      }).apply(Object.create(null), { length: 1, '0': i }), 1000)
    }
    
  • 方法五 原理:

    • 利用 eval 或者 new Function 执行字符串,然后执行过程同方法四

    代码 1:

    for (var i = 0; i < 10; i++) {
      setTimeout(eval('console.log(i)'), 1000)
    }
    

    代码 2:

    for (var i = 0; i < 10; i++) {
      setTimeout(new Function('i', 'console.log(i)')(i), 1000)
    }
    

    代码 3:

    for (var i = 0; i < 10; i++) {
      setTimeout(new Function('console.log(i)')(), 1000)
    }
    

aoyeshirenbianchou avatar Sep 20 '19 04:09 aoyeshirenbianchou

看了很多,我再加一个吧

for (var i = 0; i < 10; i++) {
  console.log(i)
}

Timi-code avatar Oct 30 '19 02:10 Timi-code

解决办法汇总

  • 方法一 原理:

    • 利用 setTimeout 函数的第三个参数,会作为回调函数的第一个参数传入
    • 利用 bind 函数部分执行的特性

    代码 1:

    for (var i = 0; i < 10; i++) {
      setTimeout(i => {
        console.log(i);
      }, 1000, i)
    }
    

    代码 2:

    for (var i = 0; i < 10; i++) {
      setTimeout(console.log, 1000, i)
    }
    

    代码 3:

    for (var i = 0; i < 10; i++) {
      setTimeout(console.log.bind(Object.create(null), i), 1000)
    }
    
  • 方法二 原理:

    • 利用 let 变量的特性 — 在每一次 for 循环的过程中,let 声明的变量会在当前的块级作用域里面(for 循环的 body 体,也即两个花括号之间的内容区域)创建一个文法环境(Lexical Environment),该环境里面包括了当前 for 循环过程中的 i具体链接

    代码 1:

    for (let i = 0; i < 10; i++) {
      setTimeout(() => {
        console.log(i);
      }, 1000)
    }
    

    等价于

    for (let i = 0; i < 10; i++) {
      let _i = i;// const _i = i;
      setTimeout(() => {
        console.log(_i);
      }, 1000)
    }
    
  • 方法三 原理:

    代码 1:

    for (var i = 0; i < 10; i++) {
      (i => {
        setTimeout(() => {
          console.log(i);
        }, 1000)
      })(i)
    }
    

    代码 2:

    for (var i = 0; i < 10; i++) {
      try {
        throw new Error(i);
      } catch ({
        message: i
      }) {
        setTimeout(() => {
          console.log(i);
        }, 1000)
      }
    }
    
  • 方法四 原理:

    • 很多其它的方案只是把 console.log(i) 放到一个函数里面,因为 setTimeout 函数的第一个参数只接受函数以及字符串,如果是 js 语句的话,js 引擎应该会自动在该语句外面包裹一层函数

    代码 1:

    for (var i = 0; i < 10; i++) {
      setTimeout(console.log(i), 1000)
    }
    

    代码 2:

    for (var i = 0; i < 10; i++) {
      setTimeout((() => {
        console.log(i);
      })(), 1000)
    }
    

    代码 3:

    for (var i = 0; i < 10; i++) {
      setTimeout((i => {
        console.log(i);
      })(i), 1000)
    }
    

    代码 4:

    for (var i = 0; i < 10; i++) {
      setTimeout((i => {
        console.log(i);
      }).call(Object.create(null), i), 1000)
    }
    

    代码 5:

    for (var i = 0; i < 10; i++) {
      setTimeout((i => {
        console.log(i);
      }).apply(Object.create(null), [i]), 1000)
    }
    

    代码 6:

    for (var i = 0; i < 10; i++) {
      setTimeout((i => {
        console.log(i);
      }).apply(Object.create(null), { length: 1, '0': i }), 1000)
    }
    
  • 方法五 原理:

    • 利用 eval 或者 new Function 执行字符串,然后执行过程同方法四

    代码 1:

    for (var i = 0; i < 10; i++) {
      setTimeout(eval('console.log(i)'), 1000)
    }
    

    代码 2:

    for (var i = 0; i < 10; i++) {
      setTimeout(new Function('i', 'console.log(i)')(i), 1000)
    }
    

    代码 3:

    for (var i = 0; i < 10; i++) {
      setTimeout(new Function('console.log(i)')(), 1000)
    }
    

经过测试,我这边直接在settimeout里的第一个参数修改成js语句会报错: 0 timers.js:118 throw new ERR_INVALID_CALLBACK(callback); ^

TypeError [ERR_INVALID_CALLBACK]: Callback must be a function. Received undefined at setTimeout (timers.js:118:11)

lanOrage avatar Dec 01 '19 12:12 lanOrage

function* delay(i){
  yield setTimeout(() => {
    console.log(i)
  },1000*i)
} 
for (var j =0 ; j< 10; j++){
  delay(j).next()
}

onionRunning avatar Dec 12 '19 02:12 onionRunning

for (var i = 0; i< 10; i++) {
  setTimeout(() => {
    console.log(i);
  }, 1000)
}

yygmind avatar Dec 16 '19 03:12 yygmind

for (var i = 0; i< 10; i++){
	setTimeout((i) => {
		console.log(i);
    }, 1000,i)
}
for (var i = 0; i< 10; i++){
    ((i) => {
        setTimeout(() => {
            console.log(i);
        }, 1000)
    })(i)
}

LiZhaoYangClub avatar Mar 13 '20 08:03 LiZhaoYangClub

for (let i = 0; i< 10; i++){ setTimeout(() => { console.log(i); }, 1000) }

thinkguo avatar Mar 26 '20 08:03 thinkguo

大智若愚 for (var i = 0; i < 10; i++) { console.log(i) }

UnrealCherry avatar Apr 30 '20 04:04 UnrealCherry

方式一

for (let i = 0; i < 10; i++) {
  setTimeout(() => {
    console.log(i);
  }, 1000 * i);
}

方式二

for (var i = 0; i < 10; i++) {
  (function (j) {
    setTimeout(() => {
      console.log(j);
    }, 1000 * j);
  })(i);
}

方式三

for (let i = 0; i < 10; i++) {
  setTimeout((i) => {
    console.log(i);
  }, 1000 * i, i);
}

方式四

let i = 0;
const timer = setInterval(() => {
  console.log(i);
  i++;
  if (i > 9) {
    clearInterval(timer);
  }
}, 1000);

Wluyao avatar May 22 '20 02:05 Wluyao

解决办法汇总

  • 方法一 原理:

    • 利用 setTimeout 函数的第三个参数,会作为回调函数的第一个参数传入
    • 利用 bind 函数部分执行的特性

    代码 1:

    for (var i = 0; i < 10; i++) {
      setTimeout(i => {
        console.log(i);
      }, 1000, i)
    }
    

    代码 2:

    for (var i = 0; i < 10; i++) {
      setTimeout(console.log, 1000, i)
    }
    

    代码 3:

    for (var i = 0; i < 10; i++) {
      setTimeout(console.log.bind(Object.create(null), i), 1000)
    }
    
  • 方法二 原理:

    • 利用 let 变量的特性 — 在每一次 for 循环的过程中,let 声明的变量会在当前的块级作用域里面(for 循环的 body 体,也即两个花括号之间的内容区域)创建一个文法环境(Lexical Environment),该环境里面包括了当前 for 循环过程中的 i具体链接

    代码 1:

    for (let i = 0; i < 10; i++) {
      setTimeout(() => {
        console.log(i);
      }, 1000)
    }
    

    等价于

    for (let i = 0; i < 10; i++) {
      let _i = i;// const _i = i;
      setTimeout(() => {
        console.log(_i);
      }, 1000)
    }
    
  • 方法三 原理:

    代码 1:

    for (var i = 0; i < 10; i++) {
      (i => {
        setTimeout(() => {
          console.log(i);
        }, 1000)
      })(i)
    }
    

    代码 2:

    for (var i = 0; i < 10; i++) {
      try {
        throw new Error(i);
      } catch ({
        message: i
      }) {
        setTimeout(() => {
          console.log(i);
        }, 1000)
      }
    }
    
  • 方法四 原理:

    • 很多其它的方案只是把 console.log(i) 放到一个函数里面,因为 setTimeout 函数的第一个参数只接受函数以及字符串,如果是 js 语句的话,js 引擎应该会自动在该语句外面包裹一层函数

    代码 1:

    for (var i = 0; i < 10; i++) {
      setTimeout(console.log(i), 1000)
    }
    

    代码 2:

    for (var i = 0; i < 10; i++) {
      setTimeout((() => {
        console.log(i);
      })(), 1000)
    }
    

    代码 3:

    for (var i = 0; i < 10; i++) {
      setTimeout((i => {
        console.log(i);
      })(i), 1000)
    }
    

    代码 4:

    for (var i = 0; i < 10; i++) {
      setTimeout((i => {
        console.log(i);
      }).call(Object.create(null), i), 1000)
    }
    

    代码 5:

    for (var i = 0; i < 10; i++) {
      setTimeout((i => {
        console.log(i);
      }).apply(Object.create(null), [i]), 1000)
    }
    

    代码 6:

    for (var i = 0; i < 10; i++) {
      setTimeout((i => {
        console.log(i);
      }).apply(Object.create(null), { length: 1, '0': i }), 1000)
    }
    
  • 方法五 原理:

    • 利用 eval 或者 new Function 执行字符串,然后执行过程同方法四

    代码 1:

    for (var i = 0; i < 10; i++) {
      setTimeout(eval('console.log(i)'), 1000)
    }
    

    代码 2:

    for (var i = 0; i < 10; i++) {
      setTimeout(new Function('i', 'console.log(i)')(i), 1000)
    }
    

    代码 3:

    for (var i = 0; i < 10; i++) {
      setTimeout(new Function('console.log(i)')(), 1000)
    }
    

感觉就是两种方法:

  1. 将变化的数值的每一个瞬间当参数传入函数
  2. 块级作用域

cutie6 avatar Jun 15 '20 15:06 cutie6

    ### 第一种 var -> let
    ### 第二种 settimeout绑定参数,回调传参
    setTimeout((i) => {
      console.log(i);
    }, 1000,i)
    ### 第三种 使用外部变量保存每一次的i
    let j = i;
    setTimeout(() => {
      console.log(j);
    }, 1000)
   ###  第四种立即执行函数传参i或者回调函数包裹立即执行函数
    ((i)=>setTimeout(() => {
      console.log(i);
    }, 1000))(i)
    setTimeout(((i) => {
      console.log(i);
    })(i), 1000)
    ### 第五种bind或者call或者apply 也是为了传参 把每一次的i绑定
    setTimeout(((i) => {
      console.log(i);
    }).call({},i), 1000)

wxthahha avatar Jun 23 '20 03:06 wxthahha

// let 块级作用域
 for (let i = 0; i < 10; i++) {
        setTimeout(() => {
            console.log(i);
        }, 1000)
    }

// 闭包
 for (var i = 0; i < 10; i++) {
        ((j) => {
            setTimeout(() => {
                console.log(j);
            }, 1000)
        })(i)
    }

// promise 异步,其实也可以用generator将i保存在堆中
 for (var i = 0; i < 10; i++) {
        new Promise((resolved, rejected) => {
            resolved(i);
        }).then((j) => {
            setTimeout(() => {
                console.log(j);
            }, 1000)
        })
    }

// try catch
for (var i = 0; i < 10; i++) {
        try {
            throw (i);
        } catch (i) {
            setTimeout(() => {
                console.log(i);
            }, 1000)
        }
    }

SnailOwO avatar Jul 02 '20 08:07 SnailOwO

//来一个没提到的
function go(i){
    setTimeout(()=>{
        console.log(i)
    }, 1000*i)
}
for(var i = 0; i < 10; i++){
    go(i);
}

jackchang2015 avatar Jul 14 '20 11:07 jackchang2015

console.log(...[0,1,2,3,4,5,6,7,8,9])

sharp08 avatar Jul 15 '20 10:07 sharp08

// 方法1

for (var i = 0; i< 10; i++){
  (function fn(i){
    setTimeout(() => {
      console.log(i);
      }, 1000)
  })(i)
}

// 方法2

for (var i = 0; i< 10; i++){
  let y = i
  setTimeout(() => {
    console.log(y);
  }, 1000)
}

// 方法3

for (let i = 0; i< 10; i++){
  setTimeout(() => {
    console.log(i);
  }, 1000)
}

zengkaiz avatar Jul 22 '20 07:07 zengkaiz

console.log(...[0,1,2,3,4,5,6,7,8,9])

are you dou 我?

zengkaiz avatar Jul 22 '20 07:07 zengkaiz

for (var i = 0; i< 10; i++){
   setTimeout(console.log, 1000, i)
}

这是最简单的!

CarberryChai avatar Aug 07 '20 07:08 CarberryChai

// 1. 通过立即执行函数,保存每一次遍历的i
// 相当于生成了 10个立即执行函数
for (var i = 0; i < 10; i++) {
  (function (i) {
    setTimeout(() => {
      console.log(i);
    }, 0);
  })(i);
}

// 2. 使用let 生成 块级作用域
for (let i = 0; i < 10; i++) {
  setTimeout(() => {
    console.log(i);
  }, 0);
}

promotion-xu avatar Aug 21 '20 02:08 promotion-xu

// 创建函数 通过函数的入参生成新的变量-----

 for (var i = 0; i < 10; i++) {
    function name(i) {
      setTimeout(() => {
        console.log(i)
      }, 1000)
    }
    name(i)
  }

为啥没人写这个 而且 闭包能 解决这道题的原因该是因为函数的入参 生成的变量保留了i 而不是闭包的问题

webXLing avatar Aug 28 '20 09:08 webXLing

  1. 解法1 将var 改为 let
{
    for (let i = 0; i< 10; i++){
        setTimeout(() => {
            console.log(i);
        }, 1000)
    }
}
  1. 解法二 利用 setTimeout 第三个参数
{
    for (var i = 0; i< 10; i++){
        setTimeout((j) => {
            console.log(j);
        }, 1000, i)
    }
}
  1. 解法三 利用闭包
{
    for (var i = 0; i< 10; i++){
        (
            function (j) {
                setTimeout(() => {
                    console.log(j);
                }, 1000);
            }
        )(i)
        
    }
}

zbyecho avatar Dec 03 '20 10:12 zbyecho

我用 es6 实现一下

function sleep (time) {
  return new Promise((resolve) => setTimeout(resolve, time));
}

async function fn() {
  for (var i = 0; i < 10; i++){ 
    await sleep(1000);
    console.log(i);
  }
}

fn();

Michael18811380328 avatar Jan 09 '21 09:01 Michael18811380328

for (var i = 0; i < 10; i++) {  
    Promise.resolve(i).then((i)=>{
        setTimeout(() => {
            console.log(i)
        }, 1000);
    })
}

chris1299 avatar Feb 07 '21 06:02 chris1299

for (var i = 0; i < 5; i++) { setTimeout(function (i) { console.log(i); }.bind(undefined, i), 1000); }

eavan5 avatar Mar 01 '21 11:03 eavan5

for (var i = 0; i < 10; i++) {
  (function () {
    var j = i;
    setTimeout(() => {
      console.log(j);
    }, 0);
  })();
}

caizihua avatar Apr 20 '21 12:04 caizihua


// 1、let
for (let i = 0; i < 10; i++) {
  setTimeout(() => {
    console.log(i)
  }, 1000)
}

// 2、setTimeout 的第三个参数
for (var i = 0; i < 10; i++) {
  setTimeout(
    (a) => {
      console.log(a)
    },
    1000,
    i
  )
}

// 3、IIFE
for (var i = 0; i < 10; i++) {
  ;(function (a) {
    setTimeout(() => {
      console.log(a)
    }, 1000)
  })(i)
}

// 4、try catch 块级作用域
for (var i = 0; i < 10; i++) {
  try {
    throw i
  } catch (e) {
    setTimeout(() => {
      console.log(e)
    }, 1000)
  }
}

// 5、bind
for (var i = 0; i < 10; i++) {
    setTimeout(((i) => {
      console.log(i)
    }).bind(null, i), 1000)
}

MrLeihe avatar Apr 24 '21 09:04 MrLeihe

  1. JavaScript引擎执行机制?
  2. 放入异步任务队列的时机很重要!
  3. 理解作用域
  4. let在 for 循环的作用域在花括号内
  5. 闭包或箭头函数,他们在干什么?
	for (var i = 0; i < 10; i++) {
		(function(j){//闭包
			setTimeout(function(){
				console.log(j);//分别输出i的值
			},1000*j)	//设置明显的时间差
		})(i);//闭包
	};

理解到考点,背解意义不大。

zhuziyi1989 avatar Apr 25 '21 03:04 zhuziyi1989

for (var i = 0; i < 10; i++) { ( function(i) { setTimeout(() => { console.log(i); }, 1000) } )(i); }; for (var i = 0; i < 10; i++) { setTimeout((i) => { console.log(i); }, 1000,i) };

gogopaner avatar Aug 24 '21 02:08 gogopaner

image

xiaohan-123 avatar Sep 20 '21 03:09 xiaohan-123

兄弟们,给你们来个邪门歪道 for (var i = 0; i< 10; i++){ setTimeout(() => { console.log(0-(i--)+10); }, 1000) }

Ljiaji avatar Oct 31 '21 01:10 Ljiaji

优秀,第三个参数可否解释下

yaoocheng avatar Nov 11 '21 06:11 yaoocheng

//方法一
for (let i = 0; i < 10; i++) {
  setTimeout(() => {
    console.log(i)
  }, 1000)
}
//方法二
for (var i = 0; i < 10; i++) {
  (function(j) {
    setTimeout(() => {
      console.log(j)
    }, 1000)
  })(i)
}
//方法三
for (var i = 0; i < 10; i++) {
  foo(i)
}

function foo(i) {
  setTimeout(() => {
    console.log(i)
  }, 1000)
}
//方法四
for (var i = 0; i < 10; i++) {
  setTimeout((j) => {
    console.log(j)
  }, 1000, i)
}
//方法五
for (var i = 0; i < 10; i++) {
  new Promise(function(resolve, reject) {
    resolve(i)
  }).then(function(i) {
    setTimeout(() => {
      console.log(i)
    }, 1000)
  })
}

xinxin-l avatar Mar 20 '22 08:03 xinxin-l

都不运行一下的吗

Yuweiai avatar Jul 12 '22 10:07 Yuweiai

正常写法:

for (var i = 0; i < 10; i++) {
    setTimeout(((i) => {
        console.log(i);
    })(i), 1000)
}

砸场子写法:

let i = 0,
timer = setInterval(() => {
    i < 10 ?
    console.log(i++) :
    clearInterval(timer);
})

牛逼

DaphnisLi avatar Aug 30 '22 05:08 DaphnisLi