JS进阶 Day1 作用域 函数进阶 结构赋值(学习笔记)

本文介绍了JavaScript中的作用域,包括局部作用域、全局作用域和作用域链,强调了避免全局变量污染的重要性。接着讨论了垃圾回收机制,如引用计数法和标记清除法。此外,还详细讲解了闭包的概念及其在实现数据私有化中的应用,同时指出闭包可能导致内存泄漏。最后,文章涵盖了函数提升、动态参数、剩余参数、展开运算符、箭头函数以及数组和对象的解构赋值用法。
摘要由CSDN通过智能技术生成

1.作用域

1)局部作用域

  • 函数作用域

    注:函数执行完毕后,函数内部的变量实际被清空了

  • 块级作用域

    在js中使用{}包裹的代码称为代码块,代码块内部声明的变量外部将{有可能}无法访问

    let声明的变量会产生块作用域,var不会产生块作用域

    const声明的常量也会产生块作用域

    不同代码块之间的变量无法相互访问

    推荐使用let和const

2)全局作用域

script标签和.js文件中的最外层就是全局变量,在此声明的变量在函数内部也可以被访问。全局作用域中声明的变量,任何其他作用域都可以被访问。

为windows对象动态添加的属性默认也是全局的,不推荐。

函数中未使用任何关键字声明的变量为全局变量,不推荐。

尽可能少的声明全局变量,防止全局变量被污染。

3)作用域链

作用域链本质上是底层的变量查找机制

在函数被执行时,会优先查找当前函数作用域中查找变量。

如果当前作用域查找不到,则会依次逐级查找父级作用域直到全局作用域。(类似于冒泡)

嵌套关系的作用域串联起来形成了作用域链。

相同作用域链中按着从小到大的规则查找变量。(先查找当层)

子作用域能够访问父作用域,父作用域无法访问子作用域。

4)JS垃圾回收机制

  • 什么是垃圾回收机制?

    简称GC(garbage collection)

    JS中内存的分配和回收都是自动完成的,内存不使用的时候,会被垃圾回收器自动回收。

    但如果不了解JS的内存管理机制,会非常容易造成内存泄漏的情况。

    内存泄漏:不再用到的内存,没有及时释放。

  • 内存生命周期

    内存分配——>内存使用——>内存回收

    内存分配:系统自动为变量、函数对象分配内存

    内存使用:读写内存,使用变量、函数

    内存回收:使用完毕,由垃圾回收自动回收不再使用的内存

    全局变量一般不会回收(关闭页面回收)

    一般情况下局部变量的值,不用了,会被自动回收

    <script>
        let num = 10
        function fn() {
            const str = 'andy'
            console.log(str)
        }
        //注:因为函数调用后 会回收str 所有多次调用后 const str不会报错
        fn()
        fn()
        fn()
    </script>
    
  • 垃圾回收算法

    • 引用计数法

      看一个对象是否指向它的引用

      跟踪记录每个值被引用的次数

      如果这个值被引用了一次,就记录一次

      多次引用会累加

      如果减少一个引用就-1

      如果引用次数为0,则释放内存

      let persopn = {
          age:18
      }
      let p = person
      person = 1
      p = null
      

    在这里插入图片描述

//如果出现以下情况 会导致大量的内存泄漏(相互引用)就不能使用引用计数
function fun(){
    let o1 = {}
    let o2 = {}
    o1.a = o2
    o2.a = o1
}
  • 标记清除法

    从根部(在JS中就是全局对象global)出发定时扫描内存中的对象。凡是能从根部到达的对象,都是还需要使用的。

    无法从根部出发触及到的对象都标记为不再使用,稍后进行回收

在这里插入图片描述

5)闭包

闭包 = 内层函数 + 外层函数的变量

//内层函数调用外层函数的变量 简单写法
function outer(){
    const a = 1
    function f(){
        console.log(a)
    }
    f()
}
outer()
 //常见闭包形式 外部可以使用函数内部的变量
// function outer() {
//     const a = 100
//     function f() {
//         console.log(a)
//     }
//     return f
// }
// outer()
// const fun = outer()
// fun()

// function outer() {
//     const a = 100
//     return function f() {
//         console.log(a)
//     }
// }
// outer()
// const fun = outer()
// fun()

function outer() {
    const a = 100
    return function f() {
        return a
    }
}
const fun = outer()
console.log(fun())
  • 闭包应用

    实现数据私有

    <script>
            function fun() {
                let i = 0
                function count() {
                    i++
                    console.log(`函数被调用了${i}`)
                }
                return count
            }
            const fn = fun()
    
        </script>
    

在这里插入图片描述

注意:闭包可能引起内存泄漏

6)变量提升

<script>
    //1.把所有var声明的变量提升到当前作用域的最前面
    //2.只提升声明,不提升赋值
    // console.log(num+"件")
    // var num = 10

    function fun() {
        console.log(num)
        var num = 10
    }
    fn()
</script>

变量提升过程:

1.把所有var声明的变量提升到当前作用域的最前面
2.只提升声明,不提升赋值

注:

变量在var声明之前被访问,变量值为undefined

let和const不存在变量提升(推荐)

2.函数进阶

1)函数提升

函数在声明之前可以被提升

 <script>
    //会把所有函数声明提升到当前作用域的最前面
    //只提升函数声明,不提升函数调用
    fn()
    function fn() {
        console.log('函数提升')
    }
</script>

注:函数表达式 必须先声明和赋值,后调用否则会报错

var fun = function(){}

2)函数参数

  • 动态参数

    arguments是函数内部内置的伪数组变量,它包含了调用函数时传入的所有实参。

    <script>
        function getSum() {
            let sum = 0
            //arguments 动态参数 只存在于函数内
            //是个伪数组
            for (let i = 0; i < arguments.length; i++) {
                sum += arguments[i]
            }
            return sum
        }
        console.log(getSum(1, 2, 3, 4, 5, 6, 7, 8, 9))
        console.log(getSum(16, 58, 79))
        console.log(getSum(1000000000000, 58, 999999999))
    </script>
    
  • 剩余参数

    将一个不定数量的参数表示为一个数组

    <script>
        function getSum(...arr) {
            console.log(arr)
        }
        getSum(1, 2)
        getSum(1, 2, 3)
    
        function getTotal(a, b, ...Arr) {
            console.log(Arr)
        }
        //返回一个空数组 1赋值给a,2赋值给b
        getTotal(1, 2)
        //返回有两个数的数组
        getTotal(1, 2, 3, 4)
        //返回有一个值的数组
        getTotal(1, 2, 3)
    </script>
    

    两者的区别:

    …是语法符号,置于最末函数形参之前,用于获取多余的参数

    借助…获取的剩余实参,是个真数组

    开发中,提倡多使用剩余参数

  • 展开运算符(…)

    <script>
        const arr1 = [1, 2, 3, 4, 5]
        console.log(...arr)
        //求最值
        console.log(Math.max(...arr))
        //合并数组
        const arr2 = [6, 7, 8, 9]
        const arr = [...arr1, ...arr2]
        console.log(arr)
    </script>
    

    注:

    不会修改原数组

    应用场景:求数组的最值、合并数组

  • 箭头函数(表达式函数)

    目的:书写更简短的函数,并不绑定this

    使用场景:适用于本来需要匿名函数的地方

    <script>
        //1.普通函数
        // const fun = function fn() {
        //     console.log(111)
        // }
        // fun()
    
        //箭头函数
        // const fun = (x) => {
        //     console.log(x)
        // }
        // fun(123)
    
        //只有一个形参 括号可以省略
        // const fun = x => {
        //     console.log(x)
        // }
        // fun(123)
    
        //只有一行代码 大括号可以省
        // const fun = x => console.log(x)
        // fun(123)
    
        //只有一行代码 return可省
        const fun = (x, y) => x + y
        console.log(fun(3, 9))
    
        //返回对象
        const fn = (uname) => ({ name: uname })
        console.log(fn('姚老师'))
    </script>
    
    • 箭头函数参数

      没有动态参数arguments,但有剩余参数

      <script>
          const getSum = (...arr) => {
              let sum = 0
              for (let i = 0; i < arr.length; i++) {
                  sum += arr[i]
              }
              return sum
          }
          const result = getSum(2, 3, 5)
          console.log(result)
      </script>
      
    • 箭头函数this

      箭头函数不会创建自己的this,它只会从自己的作用域链的上一层沿用this

      <script>
          //以前的this指向
          console.log(this)  //window
      
          function fn() {
              console.log(this)  //window
          }
          fn()
      
          const obj = {
              name: 'andy',
              sayHi: function () {
                  console.log(this)  //obj
              }
          }
          obj.sayHi()
      
          //箭头函数中的this
          //{}中是一个局部作用域 是上一层作用域的this
          const fun = () => {
              console.log(this)  //window
          }
          fun()
      
          //对象方法箭头函数
          const user = {
              uname: '嘎吱~',
              sayHi: () => {
                  console.log(this) //window
              }
          }
          user.sayHi()
      
          const people = {
              uname: '花花',
              sayHi: function () {
                  let i = 10
                  const count = () => {
                      console.log(this) //obj
                  }
                  count()
              }
          }
          people.sayHi()
      </script>
      

3.解构赋值

1)数组解构

数组解构将数组的单元值快速赋值给若干个变量的语法

<script>
    const arr = [100, 60, 80]
    //数组解构
    const [max, min, avg] = arr
    console.log(max)
</script>

典型应用:交换两个变量

let a = 1
let b = 2;
[b, a] = [a, b]
console.log(a, b)

注:记得加分号; const不能重新赋值

必须加分号的情况:立即执行函数,数组解构

<script>
    //1.立即执行函数
    // (function () { })();

    //2.使用数组
    //如果不加分号 默认为是没有换行
    // const arr = [1, 2, 3]
    const str = 'pink老师';
    [1, 2, 3].map(function (item) {
        console.log(item)
    })
</script>
  • 特殊情况

    const [a, b, c, d] = [1, 2, 3]
    console.log(a) //1
    console.log(b) //2
    console.log(c) //3
    console.log(d) //undefined
    
    const [e, f, ...arr] = [1, 2, 3, 4, 5]
    console.log(e) //1
    console.log(f) //2
    console.log(arr) //{3,4,5}
    
    //防止undefined传递 添加默认值
    const [g = 0, h = 0] = []
    console.log(g)
    console.log(h)
    
     //按需导入赋值
    const [i, j, , k] = [1, 2, 3, 4]
    console.log(i) //a
    console.log(j) //2
    console.log(k) //4
    
  • 支持多维数组

    const [a, b, [c, d]] = [1, 2, [3, 4]]
    console.log(a) //1
    console.log(b) //2
    console.log(c) //3
    

2)对象结构

快速解构属性和方法的语法

<script>
    //变量名与属性名必须相同 uname = uname
    //如果名称不相同 返回undefined
    // const { uname, age } = { uname: 'pink老师', age: 18 }
    // console.log(uname)
    // console.log(age)

    //与变量名冲突的问题
    // const uname = '花花'
    // const { uname: username, age } = { uname: 'pink老师', age: 18 }
    // console.log(username)
    // console.log(age)

    //解构数组对象
    const pig = [
        {
            uname: '佩奇',
            age: 18
        }
    ]
    const [{ uname, age }] = pig
    console.log(uname)
    console.log(age)
</script>
  • 多级对象解构

    <script>
        const pig = {
            name: '佩奇',
            family: {
                mother: '猪妈妈',
                father: '猪爸爸',
                sister: '乔治'
            },
            age: 16
        }
        const { name, family: { mother, father, sister }, age } = pig
        console.log(name)
        console.log(mother)
        console.log(father)
        console.log(sister)
        console.log(age)
    
    	const person = [
            {
                name: '佩奇',
                family: {
                    mother: '猪妈妈',
                    father: '猪爸爸',
                    sister: '乔治'
                },
                age: 16
            }
        ]
        const [{ name, family: { mother, father, sister }, age }] = person
        console.log(name)
        console.log(mother)
        console.log(father)
        console.log(sister)
        console.log(age)
    </script>
    

遍历数组forEach

被遍历的数组.forEach(function(当前数组元素,当前元素索引号){
    //函数体
})

只遍历,不返回数组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值