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

JS由浅入深的一道面试题

程序员文章站 2024-03-23 13:28:28
...

前言: 前端面试中,JS是一大热点,下面就跟着小编来看一下一道由浅入深的面试题吧。

正文: 请说出下面代码的执行结果:

for (var i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i); 
  }, 1000);
}
---------------------揭晓答案了---------------------

  因为JS是单线程的语言,所以遇到异步函数的时候,setTimeout会被放到等待队列中,当主线程上的函数执行结束之后,再去执行等待队列中的函数,如下图所示:
JS由浅入深的一道面试题
  当主线程执行完毕,此时变量i已经变成5,所以上述代码的结果是输出5个5。
  JS由浅入深的一道面试题

  问题来了:如果我想输出01234,应该如何实现呢?

  方式一:let

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

  这里就要说一下let和var的区别了,let有块级作用域,就是一个{}的作用域,而var就没有块级作用域,只有函数作用域和全局作用域,所以使用var声明的话会打印出5个5,用let声明的话会打印出01234。

  JS由浅入深的一道面试题
  方式二:函数自执行,闭包

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

  闭包延续变量的生命周期,将变量保存,所以会输出01234。同时也可以把自执行函数抽出一个函数,方便以后的覆用。

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

  JS由浅入深的一道面试题
  问题又来了:如果我想输出012345,应该如何实现呢?

  可能会有人说直接在后面添加console.log(i);不就可以了吗,如下:

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

  但是结果如下:因为会先执行主线程
  JS由浅入深的一道面试题
  那应该如何做呢?

  方案一:setTimeout延迟执行

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

  把输出5的也放到异步函数中,这样就会在上面的异步函数执行完之后在执行下面的异步函数了。
  JS由浅入深的一道面试题
  方案二:Promise 定义多个异步任务

const tasks = [];
for (var i = 0; i < 5; i++) {
  ((j) => {
    tasks.push(new Promise((reslove) => {
        setTimeout(() => {
          console.log(j);
          reslove();
        }, 1000);
      }));
  })(i);
}
// 等待所有异步任务执行完成
Promise.all(tasks).then(()=>{
  console.log(i);
})

  同理:也可以把里面的自执行函数封装成一个函数,方便以后调用,这里不进行展示。

总结: 要真正掌握JS,就要对JS活学活用,因为一点点的区别,最后的结果可能会大相径庭。

上一篇: C++的inline函数

下一篇: