JS 函数的执行时机

JS函数的要素

  1. 调用时机:JS函数的不同执行时机,会影响到函数运行的输出结果,不能通过代码本身百分百判断函数输出什么,而是要根据函数具体的执行时机。
  2. 作用域:每个函数都会默认创建一个作用域
  3. 闭包:JS函数会就近寻找最近的变量
  4. 形式参数
  5. 返回值
  6. 调用栈:进入一个函数的时候,要先把环境存下来,才能进去,有的东西越多,需要一个数组来保存,那保存的环境所在的数组叫做调用栈
  7. 函数提升
  8. arguments(除了箭头函数)
  9. this(除了箭头函数)

函数执行时机

函数调用时机不同, 产生结果就不同

let a = 1
function fn(){
    console.log(a)
}
// 不会打印任何东西,因为函数没有执行
复制代码
let a = 1
function fn(){
    console.log(a)
}
fn() // 1 
//很简单,一开始声明了 a , a 的值为1,然后调用函数 fn , 打印 a。 
复制代码
let a = 1
function fn(){
    console.log(a)
}
a = 2
fn() // 2
// 一开始声明了 a , a 的值为1,然后在函数之前将 2 赋值给 a 。 所以打印出 a 的值为2。
复制代码
let a = 1
function fn(){
    console.log(a)
}
fn() // 1
a = 2
// 这次是在函数执行后改变 a 的值,函数执行的时候,a 的值依旧为1.
复制代码
function f1(){
    let a = 1
    function f2(){
        let a = 2
        function f3(){
            console.log(a)
        }
        a = 22
        f3()
    }
    console.log(a)
    a = 100
    f2()
}
f1()
// 输出结果为 
// 1
// 22
复制代码

通过上面几个例子可以看出,函数中某个变量值的判断,需要确定函数执行的时机。

关于异步函数

关于setTimeout

//解释如下代码会打印 6 个 6

let i = 0
for(i = 0; i<6; i++){
  setTimeout(()=>{
    console.log(i)
  },0)
}
// 6
// 6
// 6
// 6
// 6
// 6
复制代码

setTimeout

  • 用于在指定的毫秒数后调用函数或计算表达式;
  • 意思就是尽快执行,而不是马上执行;
  • 可以理解为做完手头的事稍后再执行。

setTimeout是一个异步任务,执行到这里的操作会被浏览器丢到另一个任务队列里去, 浏览器这时候会继续执行for循环。for循环每进行一次,setTimeout都执行一次,但是里面的函数console.log(i)没有被执行,而是被放到了任务队列里面,等待执行,for循环了6次,就放了6次,当主线程执行完成后,才进入任务队列里面执行。这时候因为for循环结束后 i=6,所以console.log(i)输出的全部都是6。

如何理解异步呢?
异步代码不等待结果,直接进行下面的代码,所以定时器只是开启了,而没有立即执行里面的代码,等到当前运行坏境的代码执行完之后再回来执行定时器里面的代码。

总结:异步就是不等待结果的代码。

如果想要符合预期的打印0-5呢?

//方法一
//for let 配合
for(let i = 0; i<6; i++){
    setTimeout(()=>{
        console.log(i)
    },0)
}
// 0 1 2 3 4 5
//这里 let 会单独创建一个作用域 相当于有6个 i 。
复制代码
//方法二
//在for循环内部声明变量来存储 i 的值
let i
for (i = 0; i < 6; i++) {
    let x = i
    setTimeout(() => {
        console.log(x)
    })
}
// 0 1 2 3 4 5
复制代码
//方法三
//使用立即执行函数
let i = 0
for(i = 0; i < 6; i++){
    setTimeout(!function (){
    console.log(i);
}(),0)
}
// 0 1 2 3 4 5

复制代码
//方法四
//使用setTimeout 的第三个参数(回调函数)
let i = 0
for(i = 0; i < 6; i++){
  setTimeout((value)=>{
    console.log(value)
  },0,i)
}
// 0 1 2 3 4 5
//上面代码中,最后的参数i,将在主线程结束之后回调函数执行时,作为回调函数的参数value
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享