itstrive / striveCode

some demo and js Knowledge points records :cn: :cloud: :snowflake:
108 stars 83 forks source link

一道题目的思考 #9

Open itstrive opened 6 years ago

itstrive commented 6 years ago

题目是这样的:

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

}

问最后结果输出是多少?


说实话,这道题目我一眼看过去,就说是2,因为我看成 var了, 当然知道是let后,思考了一会,最后还是给了答案2

但是,最终结果是0。

欢迎大家提出自己的想法,和思考意见,希望能说出原因。

以上这些知识点如果不懂的,可以补下js基础。

当然简单说下var和let,var在for循环中定义的变量是属于全局的,而let有块级作用域(下面有图验证)

咱先讨论一个挺重要的东西:


然而,先别急,既然你知道是0了(按照答案推一下),好像能总结出一点点规律是么? 下面考一下大家的基础。

}

答案是多少? 
答案是1,因为逗号表达式取最后一个值,最后一个值是定时器的返回值,定时器执行完,返回当前是第几个计数器,就1个,所以是1。

- 题目变成:

``` javascript
setTimeout(()=>null,0);
for(
    let i= (1,2,3,setTimeout(()=>console.log(i),300));
    i<2;
    i++
){

}

答案是多少? 答案是2,之前已经定义过一个定时器了。

for(
    const i= (1,setTimeout(()=>console.log(i),300),3);
    i<2;
    i++
){

}

答案是多少? 答案是3, 逗号表达式,取最后一个,有人说,const不能修改的,人家常量。 看清楚了,我是3开始的,压根走不了循环,当然改小了肯定有报错,但是定时器里的值,还是逗号表达式的值。

说了这么多了,大家应该有自己的思考了。


说下我的思考:

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

}

这道题目,我的思考是(以下有很多都不是人话,我尽量说成人话了): 整个循环过程中,i值是会随着循环变的。 只是定时器在执行的时候,重新执行了一遍那个for循环初始的表达式,也就是逗号表达式的值。 好像这是两段程序,循环是循环,定时器是定时器。

当然for循环的初始值为表达式,`mozilla developer里有说明`:

initialization An expression (including assignment expressions) or variable declaration. Typically used to initialize a counter variable. This expression may optionally declare new variables with var or let keywords. Variables declared with var are not local to the loop, i.e. they are in the same scope the for loop is in. Variables declared with let are local to the statement. The result of this expression is discarded.

摘自: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for

不知道大家是否看懂了,是否有自己的思考。

从内存回收角度思考:

- 首先循环过程中,i的值肯定是变化的,循环结束后,i的值会被回收掉。
- 等过了一段时间(定时器)发现需要用到i,又重新开了一次,其实就是调用的初始值。

从入栈角度思考:

- 上述的程序,在压栈时候,就已经是两段程序了。压进去的定时器那段,就是一个普通的逗号表达式。
- 循环是普通的循环。

也就是题目可以拆成:

一段是: let i = (setTimeout(()=>console.log(i), 2333) , 0)

一段是:

for(
  let i = 0;
  i<2;
  i++
){

}

至于正确与否,无法验证(想验证的可以自己慢慢debugger看看),但是一定相信,循环还是咱们以前用的循环,它没有变。