Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

一道题目的思考 #9

Open
itstrive opened this issue Aug 23, 2018 · 0 comments
Open

一道题目的思考 #9

itstrive opened this issue Aug 23, 2018 · 0 comments
Labels

Comments

@itstrive
Copy link
Owner

题目是这样的:

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

问最后结果输出是多少?


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

但是,最终结果是0。

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

  • 当然这道题目考察的知识点很多, 比如: let定义变量的特点、循环初始值为表达式时结果的处理、逗号表达式、定时器、定时器的返回值等等。

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

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

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

  • 循环过程中,初始值会不会变?
    答案是肯定的,会变(建议无论有基础,没基础的大家,自己debugger下)

     for(let i=0; i<5; i++){
     	debugger;
     	console.log(i);
     }

    看图:
    var用在循环中,变量在全局,而且循环过程中初始值改了。
    2
    let用在循环中,变量在块级作用于,而且循环过程中初始值改了。
    1

  • 既然会变,那上述题目中,循环结束i应该是2才对啊?
    是的,没错(我认为完全正确),要不用了多年的for循环,竟然自己觉得是错的,不完蛋了。

    那结果为何是 0?,是的,是0,我现在给不了你答案,整篇文章也给不了,但是我会给你,我的想法和思考。


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

  • 题目变成:
for(
    let i=(1,2,3,setTimeout(()=>console.log(i),300));
    i<2;
    i++
){

}

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

  • 题目变成:
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看看),但是一定相信,循环还是咱们以前用的循环,它没有变。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant