改造下面的代码,使之输出0 - 9,写出你能想到的所有解法【算法】

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

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

这段代码输出的10次10,而不是0-9,这就是涉及到javaScript的单线程执行方式,当主线程(也就是宏任务中的同步逻辑),执行完主线程后才会去将异步线程上的代码清理赶紧(也就是定时器setimeout这个异步代码逻辑),此时i已经为10了,所以执行了10次的异步代码;

关于上面提到的JavaScript执行顺序,需要深入了解的可以看这篇文章 → 戳这里

因此我们要输出0-9,就要解决这个执行顺序

开始自闭改造

1. 方法一

原理:

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

代码 1:

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

代码 2:

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

代码3:

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

2. 方法二

原理:

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

代码 1:

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

等价于 ↑ ↓

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

3. 方法三

原理:

  • 利用函数自执行的方式,把当前 for 循环过程中的 i 传递进去,构建出块级作用域。IIFE 其实并不属于闭包的范畴。参考链接如下:
    JS之闭包与IIFE
  • 利用try…catch方式构建出块级作用域

代码 1:

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

代码 2:

for (var i = 0; i < 10; i++) {
  try {
    throw new Error(i);
  } catch ({
    message: i
  }) {
    setTimeout(() => {
      console.log(i);
    }, i * 100)
  }
}

4. 方法四

原理:

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

代码 1:

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

代码 2:

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

代码 3:

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

代码4:

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

代码 5:

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

5. 方法五

原理:

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

代码 1:

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

代码 2:

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

代码 3:

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

暂时结束

over~

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值