【JS高级】作用域和预解析

一、作用域

变量使用的范围。

1.1 函数(局部)作用域

在局部作用域声明的变量,只能在函数内部被访问,不同函数和外部无法直接访问。函数的形参也是局部变量。

1.2 块作用域

{}内部声明的变量,不同代码块之间的变量无法互相访问。

  • let 声明的变量和 const 声明的常量会产生块作用域,var 不会产生块作用域;

1.3 全局作用域

在全局申明的变量,可以在任何地方使用。

  • 为 window 对象动态添加的属性默认为全局的;
  • 函数中未使用任何关键字声明的变量为全局变量;

1.4 作用域链

变量查找机制:执行代码时,会优先在当前作用域中查找变量,如果当前作用域查找不到,则会逐级查找父级作用域直到全局作用域。

1.5 var、let 和 const

  • let 和 var 都用于声明变量,都可以只定义,不赋值。
  • const用于声明常量,常量名通常大写,必须初始化,不可修改值;
  • let 声明的变量和 const 声明的常量会产生块作用域,var 不会产生块作用域;
  • var 可重复声明一个变量,let /const 不可重复声明一个变量;
  • var 声明的变量相当于window的属性;
  • var 声明的变量可提升,let/const 不存在变量提升,不允许声明之前使用。
  • let/const 会形成暂时性死区,所以需要先定义,再使用。
  • 开发中不修改的值,数组和对象,建议用const声明,对于引用型数据,const声明的变量里面存的是地址
  • 基本数据类型的值或者引用类型的地址发生变化的时候用let。

1.6 闭包

子函数可以访问父函数中的局部变量,即使在父函数关闭以后。

  • 场景:一个作用域有权访问另一个作用域的局部变量。
  • 作用:延申变量的使用范围。
  • 缺点:容易引起内存泄漏。
  • 语法
<script>
    function f1() {
        let num = 1
        // 子函数作为返回值的形式
        return function () {
            console.log(num)
        }
    }
    let n = f1()
    n()
</script>
  • 回调函数也能访问函数内部的局部变量(作为函数的参数)
<script>
    function fn(n){
        let num=1
        n(num)
    }
    fn (function(a){console.log(a)})
</script>

二、预解析和函数参数

2.1 预解析

  • 代码在执行之前,先要进行 预解析,解析变量和函数:将声明的变量带有名字的函数,提升到当前作用域最前面,只声明和定义,不赋值和调用。
  • 变量名和函数名相同,函数优先被预解析。

2.1.1 变量提升

变量提升:变量声明之前可访问;变量被提前预解析,只声明,不赋值。

  • var 声明的变量要进行变量提升;
  • let声明的变量也会被预解析,但是未声明、初始化之前不可使用,所以我们说let 声明的变量不存在变量提升。
  • 变量提升出现在相同作用域当中。
<script>
    // 代码执行时,先进行预解析,将声明的变量提升到作用域最前面,只声明,不赋值
    // 内存:var n 
    // 内存: let m

    // 在这里变量已经被声明,没有赋值,可访问,结果为 undefined
    console.log(n)
    var n = 1

    // m已被预解析,没有赋值,不可访问
    console.log(m)
    let m = 0
</script>

2.1.2 函数提升

函数提升:函数定义之前可访问;函数被提前预解析,只定义,不调用。

  • 有名字的函数才会进行预解析,匿名函数和表达式函数不会被预解析;
  • 函数提升出现在相同作用域当中。
<script>
    // 函数预解析 函数已经被定义,不调用 
    /* 内存:function fn() {
         console.log('今天天气真好!')
     }	*/

    fn()
    function fn() {
        console.log('今天天气真好!')
    }
</script>
<script>
    // 预解析
    /* function fn() {
        // 内存: var n
        console.log(n)
        var n = 3
    }
    var n  */

    console.log(n)
    fn()
    var n = 1
    function fn() {
        // 内存: var n
        console.log(n)
        var n = 3
    }
</script>

2.2 函数参数

2.2.1 参数默认值

<script>

    // 声明函数时为形参赋值即为参数的默认值
    // 调用函数时没有传入对应实参时,参数的默认值被当做实参传入
    function fn(num1 = 1, num2 = 2) {
        let sum = num1 + num2
        console.log(sum)
    }
    fn()

    // 如果参数未自定义默认值时,参数的默认值为 undefined
    function fun(num1, num2) {
        let sum = num1 + num2
        console.log(num1, num2, sum)
    }
    fun()

    // 调用函数时若有实参传入,以传入参数为准
    function fn(num1 = 1, num2 = 2) {
        let sum = num1 + num2
        console.log(sum)
    }
    fn(3, 5)
    
</script>

在这里插入图片描述

2.2.2 动态参数

arguments 对象:是函数内部内置的伪数组变量,用于接收调用函数时传入的所有实参。

  • 作用:动态获取函数的实参。
  • 使用场景:参数不固定的时候用。
<script>

    function fn(){
        console.log(arguments)
    }
    fn(1,2,3,4,5,6)

    function fun(){
        for(let i=0;i<arguments.length;i++){
            console.log(arguments[i])
        }
    }
    fun('welcome','to','wonderlan',1,2,3)
    
</script>

在这里插入图片描述

2.2.3 剩余参数

//... 置于最末函数形参之前,用于获取剩余的实参
<script>
    // ...n 表示n接收所有剩余的参数,以数组的形式存储,并返回数组长度
    function fn(m,...n){
        console.log(m)
        console.log(n)
    }

    fn(1,2,3,4,5,6,7)

    // 此情况下等同于arguments的用法
    function fun(...m){
        console.log(m)
    }
    fun(1,2,3,4,5,6,7)
    
</script>

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值