1.作用域

  • 作用域链

    • 本质上是底层的变量查找机制
    • 在函数被执行前,会优先查找当前函数作用域中查找变量
    • 如果当前作用域查找不到则会依次逐级查找父级作用域直到全局作用域
  • JS垃圾回收机制(Garbage Collection):GC

    • 概述

      • JS 中内存的分配和回收都是自动完成的,内存在不是使用的时候会被垃圾回收期自动回收
      • 如果不了解JS的内存管理机制,容易造成内存泄漏(内存无法被回收)的情况——不在用到的内存,没有及时释放,就叫做内存泄漏
    • 内存的生命周期

      • 内存分配:当声明变量、函数、对象的时候,系统会自动分配内存
      • 内存使用:即读写内存,使用变量、函数等
      • 内存回收:使用完毕,由垃圾回收自动回收不再使用的内存
    • 算法说明 —— 引用计数

      IE采用的引用技术算法,定义内存不再使用,就是看一个对象是否由指向它的引用,没有引用就回收对象

      • 跟踪记录被引用的次数
      • 如果被引用了依次,那么记录次数累加 ++
      • 如果减少引用就减1 --
      • 如果引用次数是0,则释放内存
      • 存在问题:如果两个对象互相引用尽管他们已经不在使用,垃圾回收期不会进行回收,导致内存泄漏
      function fn() {
          let o1 = {}
          let o2 = {}
          o1.a = o2
          o2.a = o1
          return '引用计数无法回收'
      }
      fn()
      
    • 算法说明 —— 标记清楚法

      现代的IE浏览器已经不在使用引用计数算法了,现在浏览器通用的大多都是基于标记清楚算法的某些改进算法

      • 标记清除算法 “不再使用的对象” 定义为 无法达到的对象
      • 根部(在JS中就是全局对象)触发定时扫描内存中的对象,凡是能从根部到达的对象,都是还需要使用的
      • 那些无法由根部触发初级到的对象标记为不在使用,稍后会进行回收
  • 闭包

    • 闭包 = 内层函数 + 外层函数的变量
    • 作用
      • 封闭数据,实现数据私有,外部也可以访问函数内部的变量
    • 可能引起的问题
      • 内存泄漏
    // 闭包简单写法
    /* 
    function outer(){
        let a = 10
        function fn(){
            console.log(a)
        }
        fn()
    }
    outer()
    */
    
    // 常见的闭包形式(外部可以访问使用函数内部的变量)
    function outer(){
        let a = 100
        function fn(){
            console.log(a)
        }
        return fn
    }
    const fun = outer()
    fun()
    

    这样实现了数据私有,无法直接修改 a 的值

  • 变量提升

    变量提升是 JavaScript 中比较异常的现象,它允许在声明变量之前即被访问(仅存于 var 声明变量)

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

2.函数进阶

  • 函数提升

    函数提升与变量提升比较类似,是指函数在声明之前即刻被调用

    // 调用函数
    foo()
    // 声明函数
    function foo(){
        console.log("声明之前即被调用...")
    }
    
    // 不存在提升现象
    bar() // 错误
    var bar = function(){
        console.log("函数表达式不存在提升现象")
    }
    
    • 函数提升能够使函数的声明调用更灵活
    • 函数表达式不存在提升的现象
    • 函数提升出现在相同作用域中
  • 函数参数

    • 动态参数

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

    function getSum(){
        // arguments 动态参数【只存在于函数里面】
        // 伪数组,存储的是传递过来的实参
        let sum = 0
        for (let i = 0;i < arguments.length;i++){
            sum += arguments[i]
        }
        console.log(sum)
    }
    getSum(2,3,4)
    getSum(2,3,4,4,4,41,2,2)
    
    • 剩余参数【推荐使用】
      • ... 是语法符号,置于最末函数形参之前,用于获取多余的实参
      • 不是伪数组,而是真数组

    剩余参数允许我们将一个不定数量的参数表示为一个数组

    function getSum(a,b,...arr){
        console.log(arr)
    }
    getSum(2,3) // []
    getSum(2,3,4,5) //  [ 4, 5 ]
    
  • 展开运算符

    运用场景:求数组最大值最小值、合并数组等

    const arr1 = [1,2,3]
    // 展开运算符:展开数组
    console.log(...arr1) // 1 2 3
    
    // 使用场景:例如Math.max()——参数不能为数组,所以可以将数组来展开为 1,2,3的形式
    console.log(Math.max(...arr1)) // 3
    console.log(Math.min(...arr1)) // 1
    // 用来合并数组
    const arr2 = [1,2,3]
    const arr3 = [4,5,6]
    const arr = [...arr2,...arr3]
    console.log(arr) // [ 1, 2, 3, 4, 5, 6 ]
    

2.1、箭头函数

  • 基本语法

    // 函数表达式
    /* const fn = function(){
                console.log(1)
            } */
    // 箭头函数:简化函数表达式
    const fn1 = (x) => {
        console.log(x)
    }
    fn1(1)
    // 1.当只有一个行参的时候,可以省略小括号
    const fn2 = x => {
        console.log(x)
    }
    fn2(1)
    // 2.当函数体只有一行代码时,可以省略大括号
    const fn3 = x => console.log(x)
    fn3(1)
    // 3.当函数体只有一行代码,且需要返回的时候,可以省略return
    const fn4 = x => x + x
    console.log(fn4(1))
    // 4.箭头函数可以直接返回一个对象【返回值为()起来的为对象字面量】
    const fn5 = uname => ({uname:uname})
    console.log(fn5("马浩楠")) // Object { uname: "马浩楠" }
    
  • 箭头函数参数

    • 普通函数存在 arguments 动态参数
    • 箭头函数没有arguments 动态参数,但是存在剩余参数
    // 利用箭头函数的剩余参数求和
    const fun = (...arr) => {
        let sum = 0
        for (let i = 0;i < arr.length ;i++){
            sum += arr[i]
        }
        return sum
    }
    console.log(fun(2,3,4))
    
  • 箭头函数 this

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

    // 以前的this指向:谁调用,this指向谁
    console.log(this) // window
    // 普通函数
    function fun(){
        console.log(this) // window
    }
    // 对象方法中的this
    const obj = {
        name: "马浩楠",
        sayHi:function(){
            console.log(this) // obj
        }
    }
    obj.sayHi()
    
    // 箭头函数的this,指的是上一层作用域的this指向
    const fn = () => {
        console.log(this) // window
    }
    // 对象中的this
    const o = {
        name: "马浩楠",
        sayHi:() => {
            console.log(this) // window
        }
    }
    // 函数嵌套函数中的this
    const ob = {
        name:"马浩楠",
        sayHi: function() {
            console.log(this) // ob
            const count = () => {
                console.log(this) // ob
            }
            count()
        }
    }
    

    开发中,事件回调函数使用箭头函数时,this 为全局的window,因此:DOM事件回调函数为了简便,不推荐使用箭头函数

3.解构赋值

3.1、数组解构

  • 基本语法

    // 数组解构
    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) // 2
    console.log(b) // 1
    
  • js前必须加分号情况

    • 立即执行函数
    (function(){})();
    // 或者
    ;(function(){})()
    
    • 数组解构
  • 解构中特殊情况

    • 变量多 单元值少的情况
    const [a, b, c, d] = ["小米", "苹果", "华为"]
    console.log(a) // 小米
    console.log(b) // 苹果
    console.log(c) // 华为
    console.log(d) // undefined
    

    变量的数量大于单元之数量的时候,多余的变量将被赋值为 undefined

    • 变量少 单元值多的情况
    const [a, b] = ["小米", "苹果", "华为"]
    console.log(a) // 小米
    console.log(b) // 苹果
    
    • 利用剩余参数解决变量少,单元值多的情况
    const [a, b, ...tel] = ["小米", "苹果", "华为", "格力"]
    console.log(a) // 小米
    console.log(b) // 苹果
    console.log(tel) // ["华为", "格力"]
    
    • 防止undefined传递单元值的情况,可以设置默认值
    const [a = "手机", b = "华为"] = ["小米"]
    console.log(a) // 小米
    console.log(b) // 华为
    
    • 支持多维数组的解构
    const [a, [b, c] = ["小米", ["苹果", "华为"]]
    console.log(a) // 小米
    console.log(b) // 苹果
    console.log(tel) // 华为
    

3.2、对象解构

  • 基本语法

    // 解构语法 【变量名和对象属性名必须一致】
    const {uname, age} = {uname: "马浩楠", age: 22}
    // 等价于: const uname = obj.uname
    console.log(uname)
    console.log(age)
    // 对象解构的变量名:更改变量名
    const {uname:userName, age1} = {uname: "马浩楠", age1: 22}
    console.log(userName)
    console.log(age1)
    
    // 解析数组对象
    const [{name, longevity}] = [{name: "浩楠", longevity: 100}]
    console.log(name)
    console.log(longevity)
    
  • 注意点

    • 对象属性的值被赋值给与属性名相同的标量
    • 注意解构的变量名不要和外面的变量名冲突否则报错
    • 对象中找不到与变量名一致的属性时,变量值为 undefined
  • 对象多级解构

    const pig = {
        name: "佩奇",
        family: {
            mother: "猪妈妈",
            father: "猪爸爸",
            sister: "乔治"
        }
    }
    // 多级对象解构
    /* const {name, family: {mother, father, sister}} = pig
            console.log(name)
            console.log(mother)
            console.log(father)
            console.log(sister) */
    
    const person = [
        {
            name: "佩奇",
            family: {
                mother: "猪妈妈",
                father: "猪爸爸",
                sister: "乔治"
            }
        }
    ]
    const [{name, family:{mother, father, sister}}] = person
    console.log(name)
    console.log(mother)
    console.log(father)
    console.log(sister)
    
  • 遍历数组 forEach 方法

    const arr = ["red", "blue", "green"]
    arr.forEach(function(item, index){
        console.log(item) // 元素值
        console.log(index) // 索引号
    })
    // 使用箭头函数
    arr.forEach((item,index) => {
        console.log(item)
        console.log(index)
    })
    
  • 案例

image-20230810203855017.png

<body>
  <div class="list">
    <!-- <div class="item">
      <img src="" alt="">
      <p class="name"></p>
      <p class="price"></p>
    </div> -->
  </div>
  <script>
    const goodsList = [{
        id: '4001172',
        name: '称心如意手摇咖啡磨豆机咖啡豆研磨机',
        price: '289.00',
        picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg',
      },
      {
        id: '4001594',
        name: '日式黑陶功夫茶组双侧把茶具礼盒装',
        price: '288.00',
        picture: 'https://yanxuan-item.nosdn.127.net/3346b7b92f9563c7a7e24c7ead883f18.jpg',
      },
      {
        id: '4001009',
        name: '竹制干泡茶盘正方形沥水茶台品茶盘',
        price: '109.00',
        picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png',
      },
      {
        id: '4001874',
        name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器',
        price: '488.00',
        picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png',
      },
      {
        id: '4001649',
        name: '大师监制龙泉青瓷茶叶罐',
        price: '139.00',
        picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png',
      },
      {
        id: '3997185',
        name: '与众不同的口感汝瓷白酒杯套组1壶4杯',
        price: '108.00',
        picture: 'https://yanxuan-item.nosdn.127.net/8e21c794dfd3a4e8573273ddae50bce2.jpg',
      },
      {
        id: '3997403',
        name: '手工吹制更厚实白酒杯壶套装6壶6杯',
        price: '99.00',
        picture: 'https://yanxuan-item.nosdn.127.net/af2371a65f60bce152a61fc22745ff3f.jpg',
      },
      {
        id: '3998274',
        name: '德国百年工艺高端水晶玻璃红酒杯2支装',
        price: '139.00',
        picture: 'https://yanxuan-item.nosdn.127.net/8896b897b3ec6639bbd1134d66b9715c.jpg',
      },
    ]
    let str = ""
    goodsList.forEach((item, index) => {
      str += `
        <div class="item">
          <img src="${item.picture}" alt="${item.id}">
          <p class="name">${item.name}</p>
          <p class="price">${item.price}</p>
        </div>
      `
    })
    document.querySelector(".list").innerHTML = str
  </script>
</body>

4.综合案例

  • 筛选数组 filter 方法

    filter方法创建一个新的数组,新数组中的元素是通过筛选符合条件后的所有元素

    const data = [10,20,30]
    const newData = data.filter(item => {
        return item >= 20
    })
    console.log(newData) // 20,30
    

image-20230810203906252.png

<body>
  <div class="filter">
    <a data-index="1" href="javascript:;">0-100元</a>
    <a data-index="2" href="javascript:;">100-300元</a>
    <a data-index="3" href="javascript:;">300元以上</a>
    <a href="javascript:;">全部区间</a>
  </div>
  <div class="list">
    <!-- <div class="item">
      <img src="" alt="">
      <p class="name"></p>
      <p class="price"></p>
    </div> -->
  </div>
  <script>
    // 2. 初始化数据
    const goodsList = [{
        id: '4001172',
        name: '称心如意手摇咖啡磨豆机咖啡豆研磨机',
        price: '289.00',
        picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg',
      },
      {
        id: '4001594',
        name: '日式黑陶功夫茶组双侧把茶具礼盒装',
        price: '288.00',
        picture: 'https://yanxuan-item.nosdn.127.net/3346b7b92f9563c7a7e24c7ead883f18.jpg',
      },
      {
        id: '4001009',
        name: '竹制干泡茶盘正方形沥水茶台品茶盘',
        price: '109.00',
        picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png',
      },
      {
        id: '4001874',
        name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器',
        price: '488.00',
        picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png',
      },
      {
        id: '4001649',
        name: '大师监制龙泉青瓷茶叶罐',
        price: '139.00',
        picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png',
      },
      {
        id: '3997185',
        name: '与众不同的口感汝瓷白酒杯套组1壶4杯',
        price: '108.00',
        picture: 'https://yanxuan-item.nosdn.127.net/8e21c794dfd3a4e8573273ddae50bce2.jpg',
      },
      {
        id: '3997403',
        name: '手工吹制更厚实白酒杯壶套装6壶6杯',
        price: '99.00',
        picture: 'https://yanxuan-item.nosdn.127.net/af2371a65f60bce152a61fc22745ff3f.jpg',
      },
      {
        id: '3998274',
        name: '德国百年工艺高端水晶玻璃红酒杯2支装',
        price: '139.00',
        picture: 'https://yanxuan-item.nosdn.127.net/8896b897b3ec6639bbd1134d66b9715c.jpg',
      },
    ]

    function render(data){
      let str = ""
      data.forEach(item => {
        const {name, price, picture} = item
        str += `
          <div class="item">
            <img src="${picture}" alt="">
            <p class="name">${name}</p>
            <p class="price">${price}</p>
          </div>
        `
      })
      document.querySelector(".list").innerHTML = str
    }
    // 打开页面进行渲染
    render(goodsList)
    const filter = document.querySelector(".filter")
    filter.addEventListener("click", function(e){
      if(e.target.tagName === "A"){
        switch(e.target.dataset.index){
          case "1":
            render(goodsList.filter(item => item.price > 0 && item.price <= 100))
            break;
          case "2":
            render(goodsList.filter(item => item.price > 100 && item.price <= 300))
            break;
          case "3":
            render(goodsList.filter(item => item.price >= 300))
            break;
          default:
            render(goodsList)
            break;
        }
      }
    })
  </script>
</body>

results matching ""

    No results matching ""