JS由浅入深的一道面试题

news/2024/7/19 14:59:08 标签: js, 面试题, 异步函数, 闭包, let

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

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

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

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

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

  方式一:let

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

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

  在这里插入图片描述
  方式二:函数自执行,闭包

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);
}

  在这里插入图片描述
  问题又来了:如果我想输出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)

  但是结果如下:因为会先执行主线程
  在这里插入图片描述
  那应该如何做呢?

  方案一: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的也放到异步函数中,这样就会在上面的异步函数执行完之后在执行下面的异步函数了。
  在这里插入图片描述
  方案二: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活学活用,因为一点点的区别,最后的结果可能会大相径庭。


http://www.niftyadmin.cn/n/1659486.html

相关文章

Javascript高级程序设计——8.时间与日期

1、Date类型 &#xff08;1&#xff09;创建一个日期对象——不传递参数 var boxnew Date(); 上述创建对象没有传递任何的参数&#xff0c;则会自动获取当前的时间和日期 若要alert(box);则会打印出类似于“Wed NOV 2016 12&#xff1a;12&#xff1a;23 GMT” &#xff08…

看了这篇文章,让你不在害怕前端方法异步的问题

1.同步API与异步API 同步API&#xff1a;只有当前API执行完成后&#xff0c;才能继续执行下一个API&#xff1b; 异步API&#xff1a;当前API的执行不会阻塞后续代码的执行&#xff1b; 区别&#xff1a; ①同步API可以从返回值中拿到API执行的结果&#xff0c;但是异步API不…

7.目标和文件

1、目标路径 首先&#xff0c;将文件的目标路径赋值给一个目录&#xff0c;采用path变量 其次&#xff0c;&#xff08;1&#xff09;basename(变量)返回路径中文件名部分 &#xff08;2&#xff09;用dirname(变量)返回路径中目录部分 &#xff08;3&#xff09;用pathinfo(…

Vue组件传值,你真的都清楚了吗?

Vue为什么要组件化 不知道大家有没有思考过这个问题&#xff0c;什么是组件&#xff1f;Vue为什么要是组件化的开发方式呢&#xff1f;其实组件化的思想主要体现在&#xff1a;标准&#xff08;有统一的规范&#xff09;、分治&#xff08;独立完成功能&#xff09;、重用&…

8.自定义函数

1、标准函数 即系统内置函数 2、自定义函数 &#xff08;1&#xff09;采用function创建函数&#xff0c;不能跟系统内置函数重名 &#xff08;2&#xff09;函数有个特性&#xff0c;即必须被调用&#xff0c;才可以执行 &#xff08;3&#xff09;对无参数函数而言&#…

使用icomoon引入字体图标及扩充字体图标的方法

何为字体图标&#xff1f; 在说字体图标之前&#xff0c;我们先说一下图片&#xff0c;图片可以让我们的界面更加美丽&#xff0c;但是图片也是有缺点的&#xff0c;比如图片会增加总文件的大小&#xff0c;还会增加额外的HTTP请求&#xff0c;这都会降低网页的性能的。更重要…

Vue项目优化:从3.19MB到684KB的优化之路

前言 项目优化是我们前端开发人员必备的技能&#xff0c;本文以Vue项目为例&#xff0c;详细阐述优化的过程&#xff0c;看看如何使文件大小从3.19MB缩小到684KB&#xff0c;同时欢迎大家提出自己的优化方案。 项目技术栈阐述 本项目采用Vue前端框架、ElementUI组件库 优化之…

箭头函数和普通函数的区别,你知道几个呢?

箭头函数是ES6新增的写法&#xff0c;那为什么要增加这样的写法呢&#xff1f;它与普通函数有哪些区别呢&#xff1f; 区别一&#xff1a;箭头函数语法更加简洁 // 普通函数写法 function fn(x) {return function(y) {return x y;}; }// 箭头函数写法 let fn x > y > …