详解setTimeOut面试题
来源:互联网 发布:js touch 编辑:程序博客网 时间:2024/06/06 16:53
转自:https://segmentfault.com/a/1190000009017901
最近有一道很有意思的前端面试题
for (var i = 1; i <= 5; i++) { setTimeout( function timer() { console.log(i); }, i * 1000 );}//要求改动上述代码,使其依次输出1、2、3、4、5
这道题涉及到的知识点有函数的执行顺序
、闭包
、块级作用域
等。
首先,我们可以来看一下这道题原本会输出的结果是什么
如图,执行这段代码之后,立即输出了一个数字89,然后每过1秒钟输出了一个数字6
setTimeout()相关知识
在我们学习setTimeout
的时候就知道,setTimeout
有两个参数,第一个参数是回调函数,第二个参数是毫秒数,表示要执行回调函数所要延迟的时间。
但我们还需要知道的是,setTimeout
会返回一个Id
,即这个定时器的Id
,在上面的代码中其实已经创建了5个定时器,但是默认只返回了最后的一个Id
,我们可以通过将Id
赋值给一个变量,来看到这个过程。
由于方法里面没有return
任何东西出来,所以返回值为undefined
。
通过这个定时器的Id,可以使用clearTimeout(id)
方法清除掉这个定时器,这里就不再赘述了。
接下来就该讨论为什么会输出5个数字6,而不是1、2、3、4、5了。先来看一个例子
当setTimeout()
的毫秒数设置为0的时候,仍然是先执行完函数调用栈中的代码,然后立即调用定时器。这是因为,我们的定时器都被放在了一个被称为队列的数据结构中,等待上下文的可执行代码运行完毕后,才开始运行定时器,也就是定时器才刚开始计时。
例子如下:
所以在定时器的方法执行的时候,变量i已经变成了6,所以输出的全部是6。因为5个定时器所打印出来的是同一个i变量,所以想要实现输出不同的数字,就需要把每个定时器所访问的变量独立起来,这就用到了JavaScript的闭包。
作用域和闭包
我们都知道,JavaScript的变量是从外往内开放的,函数内部可以访问到外部的变量,但是外部无法访问到内部。
内部的func()
方法就形成了一个闭包,闭包用途很多,可以很好地区分开各个作用域,避免变量的混淆,但是滥用闭包也会导致性能问题。
想要使用闭包完成文章开始的面试题,可以通过以下的方式
for (var i = 1; i <= 5; i++) { (function(i){ setTimeout( function timer() { console.log(i); }, i * 1000 ); })(i);} //上面的代码是标准答案,将变量i作为参数传到闭包中//我们也可以通过作用域在函数内部把变量隔离起来//其实,在闭包内部访问i的时候,i就是一个常量for (var i = 1; i <= 5; i++) { (function(){ var s = i;//把i赋值给另外一个变量 setTimeout( function timer() { console.log(s); }, s * 1000 ); })();}//当然,也可以把setTimeout的回调函数做成一个闭包,同样能得到正确的结果。
块级作用域--关键字let
使用闭包可以得到正确的结果,原因就是改变了i的作用域,那如果我们把循环中的每个setTimeout都独立成一个作用域是不是也能实现同样的结果呢?
我们都知道,在JavaScript中,每个函数是一个独立的作用域,但是“{}”是不能形成独立作用域的。
在ES6中提出了一个新的关键字let
,就可以声明一个仅对当前“{}”
内部有作用的变量。
如图,同样可以实现。
总结
这个面试题考察了setTimeout方法的原理,间接涉及了函数调用栈。利用闭包或块级作用域可以实现想要的效果。
- 详解setTimeOut面试题
- setTimeout与循环闭包经典面试题详解
- javascript setTimeout面试题分析
- 图例详解那道 setTimeout 与循环闭包的经典面试题
- 一道JavaScript面试题(setTimeout)
- 前端面试题和setTimeout异步
- 一道有关setTimeout的面试题
- 分针网—每日分享:图例详解那道setTimeout与循环闭包的经典面试题
- 前端基础进阶(九):图例详解那道setTimeout与循环闭包的经典面试题
- 由一道面试题引发的setTimeout的用法思考
- Java面试题详解
- Linda面试题-详解
- LXLT面试题-详解
- IOS面试题详解
- IOS面试题详解
- IOS面试题详解
- C#面试题详解
- 华为面试题详解
- Tian Ji -- The Horse Racing HDU
- 关于“指针的指针”的认识(值传递、指针传递区分)
- android webview file标签点击弹出选择文件或拍照菜单
- 通俗易懂地介绍——MapReduce
- SAP UI5 MVC
- 详解setTimeOut面试题
- 使用CSDN的markdown编辑器插入数学公式
- 【JavaWeb】SpringMvc+Hibernate+MySql问题集合
- 如何将maven依赖项打进jar包
- Swift4.0 字符串常用详解
- 一个基于python简单的装饰器实例
- 3664 顺序表应用7:最大子段和之分治递归法
- UML类图新手入门级介绍
- SAP UI5 Overview