今天学习了 JS 的函数, 我来总结一下JS函数的执行时机, 以及举例来理解调用栈
本文是自己总结的, 如有问题请提供帮助, 谢谢!!!
JS 函数是如何调用的?
我们定一个函数并调用这个函数
function fn(){console.log('我被调用了')}fn()console.log('调用fn之后, 再来执行我')
上面这段代码就是简单地对函数fn 进行调用
先打印出 '我被调用了', 然后再打印出 '调用fn之后, 再来执行我'
在JS 引擎里, 上面这段代码是怎么知道我先调用了fn 呢?
知道了之后, 又怎么找到 fn 后面代码的呢?
这里就用到了 JS 引擎里的 调用栈 了
- 在执行到
fn()的时候, JS引擎 记录了所在的位置, 我们假设为一 - 然后进行了
入栈并压栈的操作 - 这样我们的调用栈里就记录了
fn() - 然后进入fn函数中, JS 引擎记录
console.log('我被调用了')的位置, 假设为二 - 继续
入栈并压栈 console.log('我被调用了')压栈之后, 被弹出, 并打印了- 然后弹出了
fn 函数, 函数没有给return的时候, 默认return undefined - 然后 JS 引擎记录
console.log('调用fn之后, 再来执行我')的位置, 假设为三 - 继续
入栈并压栈 - JS引擎, 发现没东西了, 就开始执行栈里的了
- 先入栈的后出栈
- 这就是调用栈, 依次执行, 每弹一个, 栈里就结束一个
- 一直到栈里全部结束
- 这就是
JS 函数的执行时机
下面这张图片, 结合上面的文字更好理解
解释为什么如下代码会打印 6 个 6
下面这段代码, 为什么如下代码会打印 6 个 6?
let i = 0
for(i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
因为先入栈, 然后才会弹
setTimeout 会进入任务队列中, 这是宏任务, 这里先不提
所以每次console.log(i)都会先入栈, 弹的时候在执行可是执行的时候是for结束循环的时候
这时候, i就是6了, 导致每次执行都是
写出让上面代码打印 0、1、2、3、4、5 的方法
for(let i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
利用 let会产生块级作用域
每一个栈里面的 setTimeout 的 i是独立的
除了使用 for let 配合,还有什么其他方法可以打印出 0、1、2、3、4、5
setTimeout 第三个参数
let i = 0
for(i = 0; i<6; i++){
setTimeout((j)=>{
console.log(j)
},0,i)
}
闭包 + 立即执行函数
let i = 0
for(i = 0; i<6; i++){
!function (){
setTimeout((j)=>{
console.log(j)
},0,i)
}()
}
利用 const 关键字
let i
for(i = 0; i<6; i++){
const x = i
setTimeout(()=>{
console.log(x)
})
}
总结:
-
JS函数的执行, 需要参考调用栈
-
调用栈是基于JS引擎的
-
规律就是先入栈的后出
感谢 尴尬风流 不浪漫先生(๑• . •๑) 对本文提出的问题 ! ! !