调用时机(函数要素之一)
- 一个函数的调用时机不同,产生的结果就不同
下面举几个例子来更好地解释调用时机
例1
let a = 1
function fn(){
console.log(a)
}
问:最后打印出什么?
答:不知道,因为没有调用代码,fn没有执行
例2
let a = 1
function fn(){
console.log(a)
}
fn()
打印出1,这个很好理解
知识点来了
例3
let a = 1
function fn(){
console.log(a)
} a = 2
fn()
这个函数会打印出2,因为函数后有一个a=2,console.log(a)只能确定打印的是a,而后面是先确定a=2,后调用函数fn(),所以打印出的是2
例4
let a = 1
function fn(){
console.log(a)
}
fn()
a = 2
这个函数会打印出1,因为先执行函数,之后再声明a = 2,所以执行顺序就和例3不同了
由此可见,函数的调用时机不同,可能会产生不同的结果
变态来了
- 我们知道了,函数调用时机不同,可能会产生不同的结果,但是!setTimeout会打破这一常规,当然了,这也是有理可依的
例5
let a = 1
function fn(){
setTimeout(()=>{ console.log(a) },0)
}
fn()
a = 2
这段代码会打印出2,因为 setTimeout确定了是过一段时间后打印 console.log(a), 之后执行fn()的意思是尽快打印出a的值,会先把代码执行完,再打印a的值
最最变态的来了
下面这段代码会打出6个6
let i = 0
for(i = 0; i<6; i++)
{
setTimeout(()=>{ console.log(i)
},0)
}
因为setTimeout因为setTimeout是一个异步任务,代码执行到这里的时候会先去执行别的,for循环代码执行6遍后值变为6,之后再进行console.log(i)的打印,而打印也会执行6遍,于是就会打印出6个6
问题来了,有什么办法能让这个函数打印出1,2,3,4,5吗
方法1:
for(let i = 0; i<6; i++)
{
setTimeout(()=>{
console.log(i)
},0)
}
这个代码是上个代码把let i = 0写在了for循环里面,按照正常思维来讲,答案应该是和之前一样的,但是JS这样写的话会在每次循环的时候把i复制一份留在原地,不跟随新的i变化,打印的时候就会把复制的i打印出来。这样写的话 setTimeout就没啥意义了
方法2:
for (var i = 0; i < 6; i++) {
setTimeout((i) => console.log(i), 0, i);
}
这个方法是通过通过setTimeout第三个参数来实现的,具体为啥我也讲不清楚,或许大家可以去看看MDN,找找原因
方法3:
let i
for(i = 0; i<6; i++){
!function(j){
setTimeout(()=>{
console.log(j)
},0)
}(i)
}
这个方法是用函数的闭包来解决的,在闭包中,JS函数会就近寻找最近的变量,于是i就会去寻找for循环的值来进行打印