资讯专栏INFORMATION COLUMN

分析 HTTP 203 出的一个 JS 题目

Caicloud / 2126人阅读

摘要:是上的一个栏目,主要讲一些有趣的知识。分析下上述代码中,变量是命令声明的,在全局范围内都有效,所以全局只有一个变量。

后续内容更新,请前往:个人博客,欢迎一起交流。

这是一道出自 HTTP 203 的 JS 题目。HTTP 203 是 Youtube 上的一个栏目,主要讲一些有趣的知识。

原题目是这样的:

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

// 问 2333 毫秒之后打印出什么

答案是 2333 毫秒后打印出 0。 为什么呢?

在开始分析题目之前,我们先来回顾几个知识点:

for 语法
for (语句 1; 语句 2; 语句 3) {
    被执行的代码块
}

语句 1(代码块)开始前执行;
语句 2 定义运行循环(代码块)的条件;
语句 3 在循环(代码块)已被执行之后执行;

执行的顺序为:
1.第一次循环,即初始化循环。
首先执行语句1(一般为初始化语句),再执行语句2(一般为条件判断语句),判断语句1是否符合语句2的条件,如果符合,则执行代码块,否则,停止执行,最后执行语句3。
2.其他循环:
首先判断前一次语句3的执行结果是否符合执行语句2的条件,如果符合,继续执行代码块,否则停止执行,最后执行语句3。如此往复,直到前一次语句3的执行结果不满足符合执行语句2的条件。

总的来说,执行顺序是一致的,先执行条件判断(语句2),再执行代码块,最后执行语句3。如此往复,区别在于条件判断的对象,在第一次判断时,是执行语句1,初始化的对象,后续的判断对象是执行语句3的结果。

逗号表达式

逗号表达式,因为原题目中就有使用逗号表达式let i = (setTimeout(()=>console.log(i), 2333), 0);

逗号表达式的一般形式是:表达式1,表达式2,表达式3......表达式n。
逗号表达式的求解过程是:先计算表达式1的值,再计算表达式2的值,......一直计算到表达式n的值。最后整个逗号表达式的值是表达式n的值。 看下面几个例子:

x=8*2, x*4  // 整个表达式的值为64,x的值为16

(x=8*2, x*4), x*2 // 整个表达式的值为32,x的值为16

x=(z=5, 5*2) // 整个表达式为赋值表达式,它的值为10,z的值为5,x的值为10

x=z=5, 5*2 // 整个表达式为逗号表达式,它的值为10,x和z的值都为5

逗号表达式用的地方不太多,一般情况是在给循环变量赋初值时才用得到。所以程序中并不是所有的逗号都要看成逗号运算符,尤其是在函数调用时,各个参数是用逗号隔开的,这时逗号就不是逗号运算符。

基础知识回顾完毕,我们通过几个简单示例一步一步地逼近原题目:

示例一:基础知识 for 循环
for (var i = 0; i < 2; i++) {
    console.log(i);
}

// 打印什么

这个无需多说,答案输出 0 1。

示例二:我们稍微改造下,将 log 放入 setTimeout 中
for (var i = 0; i < 2; i++) {
    setTimeout(() => console.log(i));
}

// 打印什么

答案输出 2 2。分析下:
上述代码中,变量 i 是 var 命令声明的,在全局范围内都有效,所以全局只有一个变量 i。每一次循环,变量 i 的值都会发生改变,而循环内被赋给 setTimeout 内部的 console.log(i),里面的 i 指向的就是全局的 i。也就是说,这里面所有的 i 指向的都是同一个 i,导致运行时输出的是最后一轮的 i 的值,也就是 2。

示例三:我再稍微改造下,将上述 var 改为 let。
for (let i = 0; i < 2; i++) {
    setTimeout(() => console.log(i));
}

// 打印什么

答案输出 0 1。分析下:
上述代码中,变量 i 是 let 声明的,当前的 i 只在本轮循环有效,所以每一次循环的 i 其实都是一个新的变量,所以最后输出的是0 1。你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

原题目
for(
  let i = (setTimeout(()=>console.log(i), 2333), 0); // 语句1
  i < 2; // 语句2
  i++ // 语句3
) {
  
}

// 问 2333 毫秒之后打印出什么

答案是 2333 毫秒后打印出 0。分析下:
上述题目中,变量 i 是 let 声明的,当前的 i 只在本轮循环有效,后面的表达式是逗号表达式,取最后一个值,即 i = 0,settimeout 在语句1,由于语句1只在第一次循环执行,因此 settimeout 的作用域是第一次迭代的作用域,且只执行一次。第一次迭代时 i = 0,所以答案是 2333 毫秒后打印出 0。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/97938.html

相关文章

  • Javascript混淆与解混淆的那些事儿

    摘要:抽象语法树大致流程生成然后通过类型断言进行相应的转换反编译工具全集小程序推荐逆向反编译四大工具利器年支持的反编译工具汇总原文 像软件加密与解密一样,javascript的混淆与解混淆同属于同一个范畴。道高一尺,魔高一丈。没有永恒的黑,也没有永恒的白。一切都是资本市场驱动行为,现在都流行你能为人解决什么问题,这个概念。那么市场究竟能容纳多少个能解决这种问题的利益者。JS没有秘密。 其实本...

    Yujiaao 评论0 收藏0
  • LeetCode 攻略 - 2019 年 7 月上半月汇总(55 题攻略)

    摘要:微信公众号记录截图记录截图目前关于这块算法与数据结构的安排前。已攻略返回目录目前已攻略篇文章。会根据题解以及留言内容,进行补充,并添加上提供题解的小伙伴的昵称和地址。本许可协议授权之外的使用权限可以从处获得。 Create by jsliang on 2019-07-15 11:54:45 Recently revised in 2019-07-15 15:25:25 一 目录 不...

    warmcheng 评论0 收藏0
  • LeetCode【203】:移除链表元素

    摘要:题目描述删除链表中等于给定值的所有节点。示例输入输出非递归解法思路遍历链表,找出每个待删除节点的前一个节点。特殊情况第一个节点就是待删除节点时,要单独操作。注意点当输入为时,按上面的思路删除第一个节点,剩下的链表的头节点又是待删除节点。 题目描述 删除链表中等于给定值 val 的所有节点。 示例 输入: 1->2->6->3->4->5->6, val = 6输出: 1->2->3->...

    wwolf 评论0 收藏0
  • 怎么通过$a获取到$b?某豹面试题

    摘要:原题,跳转到怎么通过获取到请用实现看一分钟之后,直觉告诉实现我不会。只知道,通过可以知道后来百度,问好朋友。真实意图这道题的意思应该是重定向后怎么获取真实地址。实际做的就是在百度或者微博服务器上一个临时重定向。 原题: $a=http://aaa.com/a,跳转到$b=http://bbb.com/b.怎么通过$a获取到$b,请用php实现 看一分钟之后,直觉告诉PHP实现我不会。...

    Flands 评论0 收藏0

发表评论

0条评论

Caicloud

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<