JS函数的执行时机和函数被调用的时机有关,函数被调用时才会被执行,调用时机不同,函数的执行结果也不同。
先通过几个例子来理解这句话:
例一:
let a = 1
function fn(){
console.log(a)
}
结果:a不会被打印,因为没有调用函数,函数未被执行。
例二:
let a = 1
function fn(){
console.log(a)
}
fn()
// 1
结果:此时会打印出1,首先前面声明了a=1,然后调用fn(),即打印出1。
例三:
let a = 1
function fn(){
console.log(a)
}
a = 2
fn()
结果:a被打印为2, 可以通过函数声明的位置确认,函数里的变量a是离函数最近的let声明的变量a,但在函数被调用前a被赋值为2。
例四:
let a = 1
function fn(){
console.log(a)
}
fn()
a = 2
// 1
结果:a被打印为1, 可以通过函数声明的位置确认,函数里的变量a是离函数最近的let声明的变量a,并且在函数调用前a的值未被改变。
例五:
let a = 1
function fn(){
setTimeout(()=>{
console.log(a)
},0)
}
fn()
a = 2
// 2
这里添加了setTimeout函数,这个函数会放在异步队列中执行(也就是同步任务执行完毕后才会执行异步任务),在这道题里面就是会先执行a=2,然后在执行setTimeout,因此打印打印结果为2。
例六:
let i = 0
for(i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
//不是 0、1、2、3、4、5
//而是 6 个 6
for循环在主线程内,setTimeout是异步方法,在任务队列里面,只有主线程执行完后,任务队列才执行,当for执行结束时候,此时的i值已经是6,所以得到结果是个6。
如何打印出0,1,2,3,4,5呢?
方法一:
for(let i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
// 0、1、2、3、4、5
和例6相比,使用let在for循环语句的圆括号之内声明赋值,在圆括号之间会有一个隐藏的作用域,并且在每次执行循环体之前,JS 引擎会把 i 在循环体的上下文中重新声明及初始化一次。
参考:
方应杭:我用了两个月的时间才理解 letzhuanlan.zhihu.com![805568730f99de59396a1fd9cda75158.png](https://i-blog.csdnimg.cn/blog_migrate/0a3098a2566becc20c8f6c47eb1ef58b.jpeg)
方法二:
for (var i = 0; i <6;i++){
!function(i){
setTimeout(()=>{
console.log(i),1000})
}(i)
}
使用立即执行函数在for循环体内声明一个局部变量,然后立即执行,也可以像let一样每次循环都得到不同的i。