函数的调用时机
每个函数都有它们的调用时机,调用的时机不同,得到的结果自然也会不同。
下面是几个常规的例子:
let a = 1
function fn(){
console.log(a)
}
fn()
// 1
// 函数的一个常规调用,打印 “1”
let a = 1
function fn(){
console.log(a)
}
a = 2
fn()
// 2
// 变量赋值为了2,所以执行函数的时候,打印 “2”
let a = 1
function fn(){
console.log(a)
}
fn()
a = 2
// 1
// a 是在函数调用之后才赋值为2,所以函数调用时打印的是 “1”
let a = 1
function fn(){
setTimeout(()=>{
console.log(a)
},0)
}
fn()
a = 2
// 2
上面代码有一个 setTimeout 函数,它会设置一个定时器,这里时间设置为 0 意味着它会在当前事件队列任务执行完后马上执行。这里的事件就是 a = 2给 a 赋值,因此最后打印输出的值为2。
let i = 0
for(i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
仍是一个类似的例子,这里的结果是会打印出 6 个 6。原因同上,setTimeout会在当前需要做的事——即for循环执行完毕之后再去执行自身内部的语句,for循环执行完毕之后,i 的值为 6,因此setTimeout会打印6次 i 的值,也就是 6 次 6。
下面这个例子,则会打印出 0、1、2、3、4、5:
for(let i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
这又是为何,因为在 for 循环里,变量 i 是由 let 声明的,且不是在全局环境声明的,这里 i 只在循环的本轮中有效,每一次循环的 i 其实都是一个新的变量。而且for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
这使得上面的代码,就近似于:
(let i = 0){
setTimeout(()=>{console.log(i)},0)
}
(let i = 1){
setTimeout(()=>{console.log(i)},0)
}
....
因此会输出 0、1、2、3、4、5。
除了上面的例子外,还可以使用 const 关键字让函数打印出 0、1、2、3、4、5:
let i
for(i = 0; i<6; i++){
const x = i
setTimeout(()=>{console.log(x)})
}
使用 const 关键字声明的变量是不得改变的,再把 x 传递给 setTimeout 内的 function 参数,即可打印出 0、1、2、3、4、5。
(End)
参考链接:
[1] MDN let语句
[2] 网道 ES6教程