JS 进阶

1. 局部作用域

  • 局部作用域分为函数作用域和块作用域

函数作用域

  • 在函数内部声明的变量只能在函数内部被访问,外部无法直接访问。

块作用域

  • 在 JavaScript 中使用 {} 包裹的代码称为代码块,代码块内部声明的变量外部将有可能无法访问。
    • let 声明的变量会产生块作用域,var 不会产生块作用域
    • const 声明的常量也会产生块作用域
    • 不同代码块之间的变量无法互相访问

2. 作用域链

  • 作用域链本质上是底层的变量查找机制
    • 在函数被执行时,会优先在当前函数作用域中查找变量
    • 如果当前作用域查找不到则会依次逐级查找父级作用域直到全局作用域

3. 垃圾回收机制

概念

  • 垃圾回收机制(Garbage Collection) 简称 GC
  • JS 中内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收

内存的生命周期

  1. 内存分配:当我们声明变量、函数、对象的时候,系统会自动为他们分配内存
  2. 内存使用:即读写内存,也就是使用变量、函数等
  3. 内存回收:使用完毕,由垃圾回收器自动回收不再使用的内存

内存泄漏:程序中分配的内存由于某种原因程序未释放或无法释放叫做内存泄漏

4. 闭包

概念

  • 一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域

    • 示例代码:

      • function outer(){
            const a = 1 ;
            function fn(){
                console.log(a)
            }
            fn()
        }
        

应用

  • 实现数据的私有

    • 示例代码:

      • let count = 1
        function fn(){
            count++
            console.log(`函数被调用${count}`次)
        }
        fn()
        fn()
        
        //闭包后
        
        function fn(){
            let count = 1
        function fun(){
            count++
            console.log(`函数被调用${count}`次)
        }
            return fun
        }
        const result = fn()
        result()
        result()
        

函数和变量

变量提升

定义

  • 允许在变量声明之前被访问(仅存在于var声明变量)

注意:

  1. 变量在未声明即被访问时会报语法错误
  2. 变量在var声明之前即被访问,变量的值为 undefined
  3. let/const 声明的变量不存在变量提升
  4. 变量提升出现在相同作用域当中
  5. 实际开发中推荐先声明再访问变量

函数提升

定义

  • 函数在定义之前可以被调用

  • 示例代码:

    • fun()
      function fun(){
          console.log('声明之前被调用')
      }
      
  • 注意:函数表达式不存在函数提升

    • fn()
      var fn = function(){
          console.log('函数表达式不存在提升现象...')
      }
      

函数参数

动态参数

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

  • 示例代码:

    • function sum(){
          let s = 0
          for(let i=0;i<arguments.length;i++){
              s+=arguments[i]
          }
          console.log(s)
      }
      sum(3,4)
      sum(1,2,3)
      
  • 总结:

    1. arguments 是一个伪数组,只存在于函数中
    2. arguments 的作用是动态获取函数的实参
    3. 可以通过for循环依次得到传递过来的实参

剩余参数

  1. 剩余参数允许我们将一个不定数量的参数表示为一个数组
  2. ...是语法符号,置于最末函数形参之前,用于获取多余的实参
  3. 借助...获取的剩余实参,是一个真数组
  • 示例代码:

    • function fun(a,...arr){
          console.log(arr)
      }
      fun(1,2,3)
      

展开运算符

  • 作用:展开运算符(...)可以将一个数组展开

  • 示例代码:

    • const arr = [1,2,3,4,5]
      console.log(...arr)
      
      //求最值
      console.log(Math.max(...arr))
      console.log(Math.min(...arr))
      //合并数组
      const arr1 = [1,2,3,]
      const arr2 = [4,5]
      const arr3 = [...arr1,...arr2]
      

箭头函数

基本语法

  • 只有一个形参的时候,可以省略小括号

    • const fn = x => {
          console.log(x)
      }
      fn(1)
      
  • 只有一行代码的时候,可以省略大括号

    • const fn = x => console.log(x)
      fn(1)
      
  • 只有一行代码的时候,可以省略 return

    • const fn = x => x + x
      fn(1)
      
  • 可以直接返回一个对象

    • const fn = (uname) => ({uname:uname})
      fn('PG')
      

函数参数

  • 箭头函数没有 arguments 动态参数,但是有 剩余 参数 ..args

  • 示例代码:

    • const getSum = (...args) => {
          let sum = 0
          for (let i = 0; i < args.length; i++){
              sum+=args[i]
          }
          return sum
      }
      console.log(getSum(1,2,3))
      

函数 this

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

  • 示例代码:

    • const fn = () => {
          console.log(this)
      }
      fn()   //输出上一层函数的this
      //对象方法箭头函数 this
      const obj = {
          uname:'PG'
          say:()=>{
              console.log(this)   //指向 window
          }
      }
      obj.say()
      
      const obj = {
          uname:'PG',
          say:function(){
          const count=()=>{
              console.log(this)   //指向 obj
          }
      }
      }
      
  • 事件回调函数使用箭头函数时,this 为全局的 window

  • 示例代码:

    • const btn = document.querySelector('.btn')
      
      btn.addEventListener('click',()=>{
          console.log(this)
      })
      
      //普通函数 this 指向 DOM 对象
      btn.addEventListener('click',function(){
          console.log(this)
      })
      

结构赋值

数组解构

  • 定义:数组解构是将数组的单元值快速批量赋值给一系列变量的简洁语法

  • 基本语法:

    • 赋值运算符 = 左侧的 [] 用于批量声明变量,右侧数组的单元值将被赋值给左侧的变量
    • 变量的顺序对应数组单元值的位置依次进行赋值操作
  • 示例代码:

    • const [max,min,avg] = [100,60,80]
      console.log(max)
      console.log(min)
      console.log(avg)
      

变量交换

  • 示例代码:

    • let a = 1
      let b = 2;   //分号必须加
      [b,a] = [a,b]
      console.log(a)
      console.log(b)
      

剩余参数

  • 示例代码:

    • //利用剩余参数解决变量少,单元值多
      const [a,b,...c] = ['兄奥','小米','华为','苹果']
      console.log(a)
      console.log(b)
      console.log(c)
      

设置默认值

  • 示例代码:

    • //防止有 undefined 传递单元值的情况,可以设置默认值
      const [a='手机',b='华为'] = ['小米']
      console.log(a)
      console.log(b)
      

按需导入

  • 示例代码:

    • //按需导入,忽略某些值
      const [a,,c,d] = ['小米','苹果','华为','格力']
      console.log(a)
      console.log(c)
      console.log(d)
      

支持多维数组的结构

  • 示例代码:

    • const [a,b] = ['苹果',['小米','华为']]
      console.log(a)
      console.log(b)
      

对象解构

  • 定义:将对象属性和方法快速批量赋值给一系列变量的简洁语法

基本语法

  1. 赋值运算符 = 左侧的{} 用于批量声明变量,右侧对象的属性值将被赋值给左侧的变量
  2. 对象属性的值将被赋值给与属性名相同的变量
  3. 注意解构的变量名不要和外面的变量名冲突否则报错
  4. 对象中找不到与变量名一致的属性时变量值为 undefined

示例代码:

const user = {
    name:'小明',
    age:18
};

const {name,age} = user
console.log(name)
console.log(age)

对象解构的变量名可以重新改名,旧变量名:新变量名

示例代码:

const {uname:username,age} = {uname:'PG',age:19}
console.log(username)
console.log(age)

解构数组对象

示例代码:

const arr = [
    {
        uname:'PG',
        age:  6
    }
]
const [{uname,age}] = arr
console.log(uanme)
console.log(age)

多级对象解构

示例代码:

const PG = {
    name: 'PG_code',
    friends:{
        bad:'you',
        good:'me'
    },
    age:18
}
const {name,friend:{bad,good}}=PG
console.log(bad)
console.log(good)

forEach 方法

  • forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数
  • 语法:
被遍历的数组.forEach(function(当前数组元素,当前元素索引号){
    
})

示例代码:

cosnt arr = ['joker','tom','PG']
const result = arr.forEach(function(item,index){
    console.log(item)
    console.log(index)
})