讲讲变量和函数提升

前提

JS引擎在读取js代码的过程中,有以下步骤

  1. 解析读取代码

  2. 执行。

  3. 注意:在JS代码执行之前,浏览器的解析器在遇到 var 变量名 和function 整个函数 提升到当前作用域的最前面。

注意事项

  1. 优先级:函数提升>变量提升

  2. 同步任务大于异步任务

  3. let有自己的块级作用域

  4. 匿名函数不会提升,会有自己的模拟块级作用域

  5. 如果在函数内部用var声明了和外部相同的变量,则优先看函数作用域当中的变量

  6. 在不同的函数里面,变量和函数提升互不影响,也不影响全局作用域(父级影响子级,子级不影响父级,3>1,3>1,3>1)

  7. 在不同的script块里面,变量和函数提升互不影响,但影响全局作用域(这里无所谓父子级之分,1+1+1=3)

直接上题目

1. var定义变量提升

    // 变量提升
    console.log(op);
    var op = 1;
    // 输出undefined

    // 相当于 
    // var op
    // console.log(op)
    // op = 1

2. var,let和setTimeout混用题型

    for(var i =0;i<=3;i++){
        setTimeout(function(){
            console.log(i);
        },0)
    }
    // 输出:4 4 4 4 

    for(let j =0;j<=3;j++){
        setTimeout(function(){
            console.log(j);
        },0)
    }
    // 输出:1 2 3 4 
    
    // 这是一个很棒的对比!

    // 1. 前提
    // js里有同步和异步的概念,且先同步后异步
    // 这里面,对于i的累加,是同步事件,放到执行栈里面,而setTimeout是异步事件,放到宏任务队列

 
    // 2. 为何有所区别
    // es6提出的let,具有块级作用域的概念,即每一个let都有自己的作用域
    // var 则是没有
    // 简单来说就是,let i=0,i=1,i=2,i=3,这些都在自己的块级作用域里面,互不影响,故能输出0,1,2,3
    // var i=0,i=1,i=2,i=3,i=4,这些是共享一个作用域的,那么后者会覆盖前者,故到输出的时候,则全为4~

3. 同步和异步题型

    // 同步和异步题型
    for(var i=0;i<=3;i++){
        console.log(i);     // 0 1 2 3
        setTimeout(function(){
            console.log(i); // 4 4 4 4 
        })
    }

    // 有了上面的2做基础,不难知道
    // 输出的0123是因为其在同步任务中,i每加1则执行一次,那么自然而然,0123都能输出
    // 而4444则是,异步任务了,此时已累加至4,自然输出就是4444

4. 子级和父级作用域

function fun(){
    var a;
    a=99;
    fun1();
    console.log(a);
    function fun1(){
        console.log(a);
        var a=10;
        console.log(a);
    }
}
fun()

// 输出:undefined 10 99
// 这个直接分析即可,记“子级作用域可以找到父级作用域,反之不可以,因为函数的销毁机制”
// 相当于
// var a
// a=99
// fun1(){
    // var a              
    // console.log(a);   undefined
    // a=10
    // console.log(a);   10
// }   
// console.log(a);   99  
// 可能有小伙伴疑惑为什么这里的a值不是fun1里面是10而是外面的99
// 这是因为那是函数作用域里面值不影响外面的作用域(简单来说就是 父级影响子级,子级不影响父级)
// 那是只要函数执行完毕,就可以立即销毁其作用域链了;同时也避免了过多占用内存的相关情况
// 故到最后一行的时候,是找不到fun1的,再往上找,也就是值99啦

5. 函数和变量优先级

function fun(){
    var a;
    a=99;
    fun1();
    console.log(a);
    function fun1(){
        console.log(a);
        var a=10;
        console.log(a);
    }
}
fun()

// 输出:undefined 10 99
// 这个直接分析即可,记“子级作用域可以找到父级作用域,反之不可以,因为函数的销毁机制”
// 相当于
// var a
// a=99
// fun1(){
    // var a              
    // console.log(a);   undefined
    // a=10
    // console.log(a);   10
// }   
// console.log(a);   99  
// 可能有小伙伴疑惑为什么这里的a值不是fun1里面是10而是外面的99
// 这是因为那是函数作用域里面值不影响外面的作用域(简单来说就是 父级影响子级,子级不影响父级)
// 那是只要函数执行完毕,就可以立即销毁其作用域链了;同时也避免了过多占用内存的相关情况
// 故到最后一行的时候,是找不到fun1的,再往上找,也就是值99啦

6. 作用域链

// 作用域链
var i=1;
function fun1(){
    console.log(i);
}
fun1();

var j=1;
function fun2(){
    var j=2;
    console.log(j);
}
fun2();

// 这个记住,如果在函数内部用var声明了和外部相同的变量,则优先看函数作用域当中的变量
// 那么看,第一个函数内部没有自己的i值,往外找,1
// 第二个函数内部有自己的j值,直接为2

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值