八、数组常用方法(filter、find、every、some)、对象(keys、values、assign)、字符串(split、includes、trim...)、日期、递归、异常处理

1. 数组常用方法

1.1 filter 过滤数组

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <script>
    // 过滤数组,返回满足筛选条件的新数组
    const arr = [10, 20, 20, 30, 40]

    // 过滤出大于20的元素
    const newArr1 = arr.filter((el, index) => {
      return el > 20
    })
    console.log(newArr1) // [30, 40]

    // 过滤出等于20的元素
    const newArr2 = arr.filter((el, index) => {
      // return el = 20
      // 上行写法错误,返回arr整个数组(=是赋值,==判断值,===判值和数据类型)

      return el === 20
    })
    console.log(newArr2) // [20, 20]
  </script>
</body>

</html>

1.2 find 返回符合条件的第一个元素

1.3 findIndex 返回符合条件的第一个元素的索引值

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <script>
    const goods = [
      {
        name: '小米',
        price: 1999
      },
      {
        name: '华为',
        price: 4999
      },
      {
        name: '苹果',
        price: 9999
      },
      {
        name: '华为',
        price: 6999
      },
    ]

    // find:返回符合条件的第一个元素值,没有则返回 undefined
    const obj1 = goods.find(el => el.name === '华为')
    console.log(obj1) // {name: '华为', price: 4999}
    const obj2 = goods.find(el => el.name === 'VIVO')
    console.log(obj2) // undefined

    // findIndex:返回满足条件的第一个元素的索引,找不到则返回-1
    const index1 = goods.findIndex(el => el.name === '华为')
    console.log(index1) // 1
    const index2 = goods.findIndex(el => el.name === 'VIVO')
    console.log(index2) // -1
    const index3 = goods.findIndex(el => el.name === '苹果')
    console.log(index3) // 2

  </script>
</body>

</html>

1.4 every 判断元素是否全部符合条件

1.5 some 判断是否有元素符合条件

1.6 reverse 反转数组

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <script>
    const arr = [10, 20, 30, 5]

    /* every(重点): 检测数组所有元素是否都符合指定条件,
    如果所有元素都通过检测返回true,否则返回false */
    const flag1 = arr.every(el => el >= 5)
    console.log(flag1) // true
    const flag2 = arr.every(el => el >= 8)
    console.log(flag2) // false

    /* some:检测数组中的元素是否满足指定条件,
    如果数组中有元素满足条件返回true,否则返回false */
    const flag3 = arr.some(el => el >= 24)
    console.log(flag3) // true
    const flag4 = arr.some(el => el >= 40)
    console.log(flag4) // false

    // reverse:反转数组,且会修改原数组
    const arr1 = [10, 20, 30, 5]
    console.log(arr1) // [10, 20, 30, 5]
    const arr2 = arr1.reverse()
    console.log(arr1, arr2) // [5, 30, 20, 10] [5, 30, 20, 10]

  </script>
</body>

</html>

1.7 案例1_学成在线

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>学成在线</title>
  <link rel="stylesheet" href="./iconfont/iconfont.css">
  <link rel="stylesheet" href="./css/base.css">
  <link rel="stylesheet" href="./css/index.css">
</head>

<body>
  <div class="course wrapper">
    <div class="info">
      <div class="avatar">
        <img src="./uploads/logo.avif" alt="">
        <span class="bili-avatar-icon"></span>
      </div>
      <p class="desc">
        <a class="user-name" href="https://space.bilibili.com/37974444" target="_blank">黑马程序员</a>
        <span>传智教育旗下官方账号</span>
      </p>
    </div>

    <div class="search">
      <p class="line">
        <span class="tip">筛 选</span>
        <a href="javascript:;" onclick="allVue()">查找所有Vue课程</a>
        <a href="javascript:;" onclick="find5K()">查找最先超过5K学习人数的课程</a>

        <!-- <a href="javascript:;" onclick="render(data)">查看所有</a> -->
        <!-- 上行代码 点击时调用render函数时不用传参 → render已设默认参数data -->
        <a href="javascript:;" onclick="render()">查看所有</a>
      </p>
      <p class="line">
        <span class="tip">判 断</span>
        <a href="javascript:;" onclick="isAdvanced()">是否都是高级课程</a>
        <a href="javascript:;" onclick="is5w()">是否有超过5万学习人数的课程</a>
      </p>
    </div>

    <!-- 精品课程 -->
    <div class="hd">
      <h3>精品推荐</h3>
    </div>
    <div class="bd">
      <ul class="common">
        <!-- <li>
          <a href="#">
            <div class="pic"><img src="./uploads/quality01.png" alt=""></div>
            <h4>JavaScript数据看板项目实战</h4>
            <p><span>高级</span> · <i>1125</i>人在学习</p>
          </a>
        </li>-->
      </ul>
    </div>
  </div>

  <script>
    let data = [
      {
        src: './uploads/quality01.png',
        title: 'JavaScript数据看板项目实战',
        num: 1125,
        tag: 'javascript',
        type: '高级',
        time: 1650988800000
      },
      {
        src: './uploads/quality02.png',
        title: 'Vue.js实战——面经全端项目',
        num: 2726,
        tag: 'vue',
        type: '高级',
        time: 1668816000000
      },
      {
        src: './uploads/quality03.png',
        title: '玩转Vue全家桶,iHRM人力资源项目',
        num: 9456,
        tag: 'vue',
        type: '高级',
        time: 1687017600000
      },
      {
        src: './uploads/quality04.png',
        title: 'Vue.js实战医疗项目——优医问诊',
        num: 7192,
        tag: 'vue',
        type: '高级',
        time: 1678809600000
      },
      {
        src: './uploads/quality05.png',
        title: '小程序实战:小兔鲜电商小程序项目',
        num: 2703,
        tag: '小程序',
        type: '高级',
        time: 1691424000000
      },
      {
        src: './uploads/quality06.png',
        title: '前端框架Flutter开发实战',
        num: 2841,
        tag: 'flutter',
        type: '高级',
        time: 1648742400000
      },
      {
        src: './uploads/quality07.png',
        title: '熟练使用React.js——极客园H5项目',
        num: 95682,
        tag: 'react',
        type: '高级',
        time: 1651852800000
      },
      {
        src: './uploads/quality08.png',
        title: '熟练使用React.js——极客园PC端项目',
        num: 904,
        tag: 'react',
        type: '高级',
        time: 1646150400000
      },
      {
        src: './uploads/quality09.png',
        title: '前端实用技术,Fetch API 实战',
        num: 1516,
        tag: 'fetch',
        type: '高级',
        time: 1660060800000
      },
      {
        src: './uploads/quality10.png',
        title: '前端高级Node.js零基础入门教程',
        num: 2766,
        tag: 'nodejs',
        type: '高级',
        time: 1675008000000
      }
    ]

    // 查找所有Vue视频(filter)
    function allVue() {
      // console.log(111)
      // 筛选出tag属性值为'vue'的元素,返回新数组

      /* const arrAllVue = data.filter((el) => {
        return el.tag === 'vue'
      }) */
      // 箭头函数简写 一个参数省略(),函数体一行代码省略return和{}
      const arrAllVue = data.filter(el => el.tag === 'vue')
      render(arrAllVue)
    }

    // 查找最先超过5K学习人数(find)
    function find5K() {
      // 方法1. find
      /* const arrFind5K = []
      arrFind5K[0] = data.find(el => el.num > 5000)
      console.log(arrFind5K)
      render(arrFind5K) */
      // 方法2. findIndex
      /* const index = data.findIndex(el => el.num > 5000)
      const arrFind5K1 = []
      arrFind5K1[0] = data[index]
      render(arrFind5K1) */

      // 课上方法
      const obj = data.find(el => el.num > 5000)
      render([obj])
    }

    // 是否都是高级内容
    function isAdvanced() {
      // const flag = data.every(el => el.type === '高级')
      // alert(flag) // true
      /* if (flag === true) {
        alert('是')
      } else {
        alert('否')
      } */
      // flag === true ? alert('是') : alert('否')
      // flag ? alert('是') : alert('否')
      // alert(flag === true ? '是' : '否')
      // alert(flag ? '是' : '否')

      data.every(el => el.type === '高级') ? alert('是') : alert('否')
    }

    // 是否有超过5万学习人数的内容
    function is5w() {
      // const flag = data.some(el => el.num > 50000)
      // alert(flag) // true

      data.some(el => el.num > 50000) ? alert('是') : alert('否')
    }


    // 渲染函数
    render()
    // arr形参默认值为data。默认渲染data数组中全部元素
    function render(arr = data) {
      const str = arr.map(item => {
        const { src, title, num, time } = item

        // 格式化处理时间
        const formatTime = new Date(time).toLocaleDateString()

        return `
          <li>
            <a href="#">
              <div class="pic">
                <img src="${src}" alt="">
              </div>
              <h4>${title}</h4>
              <p><span>高级</span> · <i>${num}</i>人在学习</p>
              <span class="date">${formatTime}</span>
            </a>
          </li>
        `
      }).join('')

      document.querySelector('.bd ul').innerHTML = str
    }
  </script>
</body>

</html>

2. 对象常用方法

2.1 Object.keys() 获取对象键

2.2 Object.values() 获取对象值

2.3 Object. assign() 对象深拷贝

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <script>
    const pig = {
      name: '佩奇',
      age: 6
    }
    // 1. Object.keys() 获取对象中所有属性(键),返回为一个数组
    const arr1 = Object.keys(pig)
    console.log(arr1) // ['name', 'age']

    // 2. Object.values() 获取对象中所有属性值,返回为一个数组
    const arr2 = Object.values(pig)
    console.log(arr2) // ['佩奇', 6]

    // 3. Object.assign() 常用于对象拷贝(深拷贝)
    const obj1 = {}
    Object.assign(obj1, pig)

    pig.name = 'peiqi'
    console.log(pig) // {name: 'peiqi', age: 6}
    console.log(obj1) // {name: '佩奇', age: 6}

    const zhu = pig // 浅拷贝 修改一个另一个跟着变

  </script>
</body>

</html>

2.4 案例2_拼接字符串

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div class="box1"></div>
  <div class="box2"></div>
  <script>
    const spec = { size: '40cm*40cm', color: '黑色' }

    // 方式一:对象.属性 +
    const box1 = document.querySelector('.box1')
    console.log(spec.size + '/' + spec.color) // 40cm*40cm/黑色
    box1.innerHTML = spec.size + '/' + spec.color

    // 方式二. values().join()
    const box2 = document.querySelector('.box2')
    console.log(Object.values(spec).join('/')) // 40cm*40cm/黑色
    box2.innerHTML = Object.values(spec).join('/')
  </script>
</body>

</html>

3. 字符串常用方法

3.1 length 字符串长度

3.2 split 将字符串拆分成数组

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <!-- 
    length 用来获取字符串的长度(重点)
    split('分隔符')用来将字符串拆分成数组(重点)
  -->
  <script>
    const str = '黑马程序员'
    console.log(str.length) // 5
    console.log(str.split('')) // ['黑', '马', '程', '序', '员']
    console.log(str.split('').reverse().join('')) // 员序程马黑

    const str1 = '小米,华为,苹果'
    console.log(str1.length) // 8
    console.log(str1.split(',')) // ['小米', '华为', '苹果']

  </script>
</body>

</html>

3.3 案例3_渲染赠品

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>赠品小案例</title>
  <style>
    .tag {
      display: block;
    }
  </style>
</head>

<body>
  <p class="name1">
    <!-- <span class="tag"></span> -->
  </p>
  <p class="name2"></p>

  <script>
    const gift = '50g茶叶,清洗球'

    // 分割为数组 → map:标签字符串 → 追加内容到 p 标签
    const str = gift.split(',').map(el => `<span class="tag">[赠品]${el}</span>`).join('')
    document.querySelector('.name1').innerHTML = str

    // 分割为数组
    const arr = gift.split(',')
    // map+join
    const str1 = arr.map(el => `<span class="tag">[赠品]${el}</span>`).join('')
    document.querySelector('.name2').innerHTML = str1
  </script>
</body>

</html>

3.4 substring、startsWith、endsWith、includes

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <script>
    const str = '传智播客传递知识'

    // 0. substring (需要截取的第一个字符的索引l[,结束的索引号]) 用于字符串截取(重点)
    // 包含开始,不包含结束位置的字符串(左闭右开)
    console.log(str.substring(0, 3)) // 传智播
    // 不写结束位置索引,表示从开始到最后
    console.log(str.substring(1)) // 智播客传递知识
    // 不写开始位置索引
    // console.log(str.substring( , 2)) // 编辑器报错

    // 1. startsWith(检测字符,[检测位置]) (重点)
    // 检测是否以某个/些字符开头,返回布尔值
    console.log(str.startsWith('传智')) // true
    console.log(str.startsWith('智')) // false
    console.log(str.startsWith('智', 2)) // false
    console.log(str.startsWith('智', 1)) // true

    // 2. endsWith(检测字符,[字符串长度])
    // 检测是否以某个/些字符结尾,返回布尔值
    console.log(str.length) // 8
    console.log(str.endsWith('知识')) // true
    console.log(str.endsWith('知', 8)) // false
    console.log(str.endsWith('识', 8)) // true

    const str1 = "To be, or not to be, that is the question."
    // 3. includes(搜索的字符,[检测位置])
    // 判断一个字符串是否 包含 在另外一个字符串中,返回布尔值
    console.log(str1.length) // 42
    console.log(str1.includes('is', 25)) // true
    console.log(str1.includes('is', 35)) // false

  </script>
</body>

</html>

3.5 trim、toUpperCase、toLowerCase、indexOf

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <script>
    // 1. 字符串trim方法: 可以去除字符串两侧的空格,返回一个新的字符串,而不修改原始字符串
    const str = ' pi nk '
    console.log(str.length) // 7
    console.log(str.trim()) // pi nk
    console.log(str.trim().length) // 5

    // 这是用户输入的内容
    const content = '         '
    console.log(content.length) // 9
    console.log(content.trim()) // (空)
    console.log(content.trim().length) // 0

    // 2. toUpperCase 用于将字母转换成大写
    console.log(str.trim().toUpperCase()) // PI NK
    const str1 = 'Hello'
    console.log(str1.toUpperCase()) // HELLO

    const str2 = 'HELLO'
    // 3. toLowerCase 用于将字母转换成小写
    console.log(str1.toLowerCase()) // hello
    console.log(str2.toLowerCase()) // hello

    // 4. indexOf 检测是否包含某字符,包含返回索引,不包含返回-1
    console.log(str2.indexOf('H')) // 0
    console.log(str2.indexOf('LL')) // 2
    console.log(str2.indexOf('H1')) // -1

  </script>
</body>

</html>

4. 日期

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <!-- 
    日期对象:用来表示日期和时间的对象
    作用:可以得到当前系统日期和时间
  -->
  <script>
    // 获得当前日期
    const date1 = new Date()
    console.log(date1) // Wed Nov 20 2024 15:24:25 GMT+0800 (中国标准时间)
    // 获得年份
    console.log(date1.getFullYear()) // 2024
    // 获得月份 值为0-11对应实际1-12
    console.log(date1.getMonth()) // 10
    // 获取月份中的每一天
    console.log(date1.getDate()) // 20
    // 获取星期 0-6 0为周日
    console.log(date1.getDay()) // 3
    // 获取小时
    console.log(date1.getHours()) // 15
    // 获取分钟
    console.log(date1.getMinutes()) // 24
    // 获取秒
    console.log(date1.getSeconds()) // 25

    // 获得指定日期
    const date2 = new Date('2025-1-1')
    console.log(date2) // Wed Jan 01 2025 00:00:00 GMT+0800 (中国标准时间)

  </script>
</body>

</html>
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <script>
    const date = new Date()
    console.log(date.toLocaleString()) // 2024/11/20 15:47:47
    console.log(date.toLocaleDateString()) // 2024/11/20
    console.log(date.toLocaleTimeString()) // 15:47:47
    //  UTC(协调世界时); GMT,即格林尼治标准时间,也是 UTC 的另一种说法
    console.log(date.toUTCString()) // Wed, 20 Nov 2024 07:47:47 GMT

    // toLocaleDateString
    // 时间戳(毫秒数)
    const time = 1651852800000
    const formatTime = new Date(time).toLocaleDateString()
    console.log(formatTime) // 2022/5/7

  </script>
</body>

</html>

5. 递归函数

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <script>
    // 递归函数:函数内部自己调用自己
    // 由于递归很容易发生“栈溢出”错误(stack overflow),所以记得添加退出条件

    /* function fn1() {
      console.log(1)
      fn1()
    }
    fn1() */
    // 最终报错 Uncaught RangeError: Maximum call stack size exceeded 栈溢出

    let num = 0
    function fn2() {
      console.log(num)
      num++
      if (num < 5) {
        fn2()
      }
    }
    fn2()

  </script>
</body>

</html>

案例4_扁平化处理数据

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="index.css">
</head>

<body>
  <section class="container">
    <div class="department">
      <h3>本公司所有员工</h3>
      <ul>
        <!-- <li>
          <img class="avatar" src="./imgs/user3.jpg" alt="">
          <span class="username">Jack</span>
          <span class="born-time">2023-10-1</span>
          <span class="sex">男</span>
        </li> -->
      </ul>
    </div>
  </section>
  <script>
    const treeData = [
      {
        id: 1,
        departmentName: '人力资源部',
        parentId: null,
        children: [
          {
            id: 12,
            username: '张三',
            avatar: './imgs/user1.jpg',
            sex: '男',
            birth: 1693039237877,
            parentId: 1,
            children: [
              {
                id: 113,
                username: '李华',
                avatar: './imgs/user3.jpg',
                sex: '男',
                birth: 1693039237877,
                parentId: 1,
                children: [],
              }
            ],
          },
          {
            id: 13,
            username: '张浩',
            avatar: './imgs/user3.jpg',
            sex: '男',
            birth: 1693039237877,
            parentId: 1,
            children: [],
          },
        ],
      },
      {
        id: 2,
        departmentName: '技术部',
        parentId: null,
        children: [
          {
            id: 24,
            username: '李四',
            avatar: './imgs/user2.jpg',
            sex: '男',
            birth: 1693039237877,
            parentId: 2,
            children: [],
          },
        ],
      },
    ]

    /* if (children.length !== 0) {
      fn()
    } */

    // 树形列表 转 列表,过滤出 员工(有parentId)渲染 为 li 标签
    function fn(array) {
      let arr = []
      array.forEach(element => {
        // 解构对象
        const { children, ...other } = element
        arr.push(other)
        if (children.length !== 0) {
          arr.push(...fn(children))
          // fn(children)
        }
      })
      console.log(arr)
      return arr
    }

    const res = fn(treeData)
    // console.log(res)

    // 筛选res 将员工追加到新数组res1
    const res1 = res.filter(element => {
      // return Boolean(element.parentId) === true
      // 隐式转换 
      return element.parentId
    })
    // console.log(res1)

    // map+join 迭代res1数组并拼接字符串
    const str = res1.map(element => {
      const { avatar, username, birth, sex } = element
      const time = new Date(birth).toLocaleDateString()
      return `
        <li>
          <img class="avatar" src="${avatar}" alt="">
          <span class="username">${username}</span>
          <span class="born-time">${time}</span>
          <span class="sex">${sex}</span>
        </li>
      `
    }).join('')
    // console.log(str)
    document.querySelector('ul').innerHTML = str
  </script>
</body>

</html>

6. 作业

6.1 数组常用方法

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    // 第一题:能够实现map 映射得到新数组
    fn1()
    function fn1() {
      // 原数组
      const input = [
        '生煎',
        '灌汤包',
        '水饺',
        '汉堡',
      ]

      // 请把input数组转换为以下格式:
      const output = [
        {
          label: '生煎',
          value: '生煎',
        },
        {
          label: '灌汤包',
          value: '灌汤包',
        },
        {
          label: '水饺',
          value: '水饺',
        },
        {
          label: '汉堡',
          value: '汉堡',
        },
      ]

      // 填入代码
      const newArr = input.map(el => {
        return ({
          label: el,
          value: el,
        })
      })
      console.log(newArr)

    }


    // 第二题:
    fn2()
    function fn2() {
      //  已知有以下数据:
      const data = [
        {
          sku: '1001',
          name: 'iPhone 7 Plus 128G 玫瑰金色 移动联通电信4G手机',
          is5G: false,
          price: 6188,
          count: 100, // 库存
          suggestions: [
            '1002',
            '1003',
            '1004',
          ], // 相关推荐
        },
        {
          sku: '1002',
          name: 'iPhone 14 Pro 256G 深空灰色 移动联通电信5G手机',
          is5G: true,
          price: 9999,
          count: 100,
          suggestions: [
            '1001',
            '1003',
          ],
        },
        {
          sku: '1003',
          name: 'iPhone 14 Pro Max 256G 深空灰色 移动联通电信5G手机',
          is5G: true,
          price: 10999,
          count: 0,
          suggestions: [
            '1001',
            '1002',
          ],
        },
        {
          sku: '1004',
          name: 'iPhone 14 Pro Max 256G 白色 移动联通电信5G手机',
          is5G: true,
          price: 10999,
          count: 9,
          suggestions: [
            '1001',
          ],
        },
      ]

      // 请完成以下需求:
      // 1. 找出所有5G手机
      const newData1 = data.filter(el => {
        return el.is5G === true
      })
      console.log(newData1)

      // 2. 找出所有有货的手机
      const newData2 = data.filter(el => {
        return el.count > 0
      })
      console.log(newData2)

      // 3. 找出所有有货的5G手机
      const newData3 = data.filter(el => {
        return el.is5G === true && el.count > 0
      })
      console.log(newData3) // 

      // 4. 找出所有有货的5G手机的总价格(数量 * 单价)
      const num = newData3.reduce((prev, current) => {
        return prev + current.price * current.count
      }, 0)
      console.log(num) // 1098891

    }

    // 第三题:
    fn3()
    function fn3() {
      // 有如下数据
      const data = [
        {
          id: '1faa0e81', // 快递单号
          from: { // 发件人信息
            name: '张三',
            id: '1412908431238',
            phone: '13800138000',
            address: '北京市朝阳区望京soho',
          },
          to: { // 收件人信息
            name: '李四',
            id: '1412908431239',
            phone: '13800138001',
            address: '北京市海淀区西二旗',
          },
          timestamp: 1610000000000, // 时间戳
          status: 'pending', // 状态 pending在途中 resolved已签收 rejected拒签
          goodsType: 'food', // 类型 food食品 electronic电子
          price: 18,  // 价格
          type: '次日达', // 快递类型
        },
        {
          id: '1faa0e82',
          from: {
            name: '张武',
            id: '1412908431240',
            phone: '13800138002',
            address: '重庆市渝中区渝中路',
          },
          to: {
            name: '李六',
            id: '1412908431241',
            phone: '13800138003',
            address: '重庆市渝北区渝北路',
          },
          timestamp: 1610000123123,
          status: 'resolved',
          goodsType: 'electronics',
          price: 188,
          type: '次日达',
        },
        {
          id: '1faa0e83',
          from: {
            name: '赵信',
            id: '1412908431242',
            phone: '13800138004',
            address: '上海市浦东新区张江高科',
          },
          to: {
            name: '王9',
            id: '1412908431243',
            phone: '13800138005',
            address: '深圳市南山区科技园',
          },
          timestamp: 1610000123124,
          status: 'pending',
          goodsType: 'food',
          price: 18,
          type: '次日达',
        },
        {
          id: '1faa0e84',
          from: {
            name: '蛮王',
            id: '1412908431244',
            phone: '13800138006',
            address: '重庆市渝中区千与千寻小区',
          },
          to: {
            name: '艾希',
            id: '1412908431245',
            phone: '13800138007',
            address: '重庆市渝北区中央公园',
          },
          timestamp: 1610000123125,
          status: 'rejected',
          goodsType: 'flowers',
          price: 99,
          type: '隔日达',
        },
      ]

      // 请完成以下需求

      // 1. 找出所有food类型的订单
      const data3new1 = data.filter(el => {
        return el.goodsType === 'food'
      })
      console.log(data3new1)

      // 2. 找出所有次日达的订单
      const data3new2 = data.filter(el => {
        return el.type === '次日达'
      })
      console.log(data3new2)

      // 3. 找出所有次日达的food类型的订单
      const data3new3 = data.filter(el => {
        return el.goodsType === 'food' && el.type === '次日达'
      })
      console.log(data3new3)

      // 4. 统计快递的拒签率(rejected为退回)
      // for遍历
      let num = 0
      for (let i = 0; i < data.length; i++) {
        data[i].status === 'rejected' ? num++ : num
      }
      console.log(`快递的拒签率为${(num / data.length) * 100}%`)
      // forEach遍历
      let num1 = 0
      data.forEach(element => {
        element.status === 'rejected' ? num1++ : num1
      })
      console.log(`快递的拒签率为${(num1 / data.length) * 100}%`)

      // 5. 找出所有在途中的订单(即pending状态的订单)
      const data3new5 = data.filter(el => {
        return el.status === 'pending'
      })
      console.log(data3new5)
    }



    // --------------------------------------------------------------
    // 封装函数,求得数组中的最大值
    function getMax(arrry) {
      // 填入代码
      let max = arrry[0]
      for (let i = 1; i < arrry.length; i++) {
        max = max > arrry[i] ? max : arrry[i]
      }
      return max
    }
    let arr = [1, 6, 2, 8, 11, 5]
    let max = getMax(arr)
    console.log(max) // 11


    // --------------------------------------------------------------
    // 封装函数,求得传入数组元素的和
    function getSum(arr) {
      // 填入代码
      let sum = 0
      arr.forEach(element => {
        sum += element
      })
      return sum
    }
    let arr2 = [3, 9, 9, 2, 7, 5]
    let sum2 = getSum(arr2)
    console.log(sum2) // 35


    // --------------------------------------------------------------
    // 封装函数,求得传入数组⾥⼤于 5 的和
    function getLargeSum(arr) {
      // 填入代码
      let sum = arr.filter(el => el > 5).reduce((prev, current) => {
        return prev + current
      }, 0)
      return sum
    }

    let arr3 = [4, 9, 6, 90, 3, 11]
    let sum3 = getLargeSum(arr3)
    console.log(sum3) // 116

    // --------------------------------------------------------------
    // 封装函数,对数组,按照价格进行升序排序
    function sortByAsc(arr) {
      // 填入代码
      return arr.sort((a, b) => a.price - b.price)
    }
    const arr4 = [
      { id: 1, name: '茶杯', price: 18 },
      { id: 2, name: '电视机', price: 2000 },
      { id: 3, name: '牙刷', price: 8 },
      { id: 4, name: '电脑', price: 5000 },
    ]
    const res4 = sortByAsc(arr4)
    console.log(res4)

    // ---------------------------------------------------------------
    // 封装函数,将学生数组中的所有姓名,存入成一个新数组,
    // 并过滤掉小强 => 得到 ['小明', '小丽', '小美']
    function getNames(arr) {
      // 填入代码
      const newArr = arr.map(el => {
        return el.name
      }).filter(el => {
        return el !== '小强'
      })
      return newArr
    }
    const arr5 = [
      { id: 1, name: '小强', score: 18 },
      { id: 2, name: '小明', score: 2000 },
      { id: 3, name: '小丽', score: 8 },
      { id: 4, name: '小美', score: 5000 },
    ]
    const res5 = getNames(arr5)
    console.log(res5) // ['小明', '小丽', '小美']
  </script>
</body>

</html>

6.2 收藏夹

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="./fonts/iconfont.css">
  <link rel="stylesheet" href="./css/index.css">
</head>

<body>
  <div class="container">
    <h1>收藏夹</h1>

    <div class="list">
      <div class="title">
        <h2>收藏夹栏</h2>
        <div class="tools">
          <!-- 显示全部 -->
          <span onclick="render()"><i class="iconfont icon-eye"></i>显示全部</span>
          <!-- 搜索-放大镜 -->
          <span onclick="search()"><i class="iconfont icon-fangdajing"></i>搜索</span>
          <!-- 添加文件夹 -->
          <span onclick="add()"><i class="iconfont icon-24gf-folderPlus"></i>添加</span>
        </div>
      </div>
      <ul id="listUl">
        <li>
          <p><i class="iconfont icon-24gf-folderOpen"></i> Lesson</p>
          <!-- 删除 -->
          <i class="iconfont icon-guanbi" onclick="del(0)"></i>
        </li>
      </ul>
    </div>
  </div>

  <script>
    // 默认渲染的收藏夹
    let arr = [
      'Vue2',
      'Vue3',
      'React',
      'Uni-app',
      'JS',
      'TS',
    ]

    render()
    // 功能1:渲染函数
    function render(array = arr) {
      const str = array.map((el, index) => {
        return `
          <li>
            <p><i class="iconfont icon-24gf-folderOpen"></i>${el}</p>
            <i class="iconfont icon-guanbi" onclick="del(${index})"></i>
          </li>
        `
      }).join('')
      document.querySelector('#listUl').innerHTML = str
    }

    // 功能2:删除功能
    function del(index) {
      arr.splice(index, 1)
      render(arr)
    }

    // 功能3:添加功能
    function add() {
      let str = prompt('输入添加的收藏夹名称')
      /* if (str.trim().length <= 0) {
        alert('请正确输入')
        return
      } */
      if (!str.trim()) {
        alert('请正确输入')
        return
      }
      arr.unshift(str)
      render()
    }

    // 功能4:搜索功能
    function search() {
      const lesson = prompt('请输入搜索的收藏夹名称')
      const newArr = arr.filter(el => {
        // return el.includes(`${lesson}`)

        // 模糊搜索,不区分大小写
        return el.toLowerCase().includes(`${lesson.trim().toLowerCase()}`)
      })
      render(newArr)
    }
  </script>
</body>

</html>

6.3 判断是否为数组

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <script>
    // 通过 Array.isArray() 方法来判断以下数据是否为数组

    const arr = []
    const likeArray = { 0: 'apple', 1: 'banner', length: 2 }
    console.log(Array.isArray(arr)) // true
    console.log(Array.isArray(likeArray)) // false

  </script>
</body>

</html>

6.4 flat

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <script>
    // 通过flat方法实现 [[1, 2], [3, [4, 5]], 6],处理得到新数组 [1, 2, 3, 4, 5, 6]

    const arr = [[1, 2], [3, [4, 5]], 6]
    const newArr = arr.flat().flat()
    console.log(newArr) // [1, 2, 3, 4, 5, 6]

    const newArr1 = arr.flat(1)
    console.log(newArr1) // [1, 2, 3, [4, 5], 6]

    const newArr2 = arr.flat(2)
    console.log(newArr2) // [1, 2, 3, 4, 5, 6]

  </script>
</body>

</html>

6.5 对象深拷贝

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <script>
    // 递归实现深拷贝 - 简版实现对象和数组的拷贝
    const obj = {
      name: '佩奇',
      family: {
        father: '猪爸爸',
      },
      hobby: ['跳泥坑', '唱歌'],
    }
    console.log(obj)

    /* const pig = {}
    Object.assign(pig, obj)
    console.log(pig) */

    // 封装深拷贝函数 cloneDeep()
    function cloneDeep(oldObj) {
      // 先判断拷贝的是数组还是对象
      const newObj = Array.isArray(oldObj) ? [] : {}

      // 遍历拷贝属性和值
      for (let k in oldObj) {
        // console.log(k)  // k 是属性
        // console.log(oldObj[k])  // oldObj[k] 是属性值
        // 把旧对象的值给新对象的属性
        if (typeof oldObj[k] === 'object') {
          // 如果属性值是引用数据类型,则需要递归再次拷贝
          newObj[k] = cloneDeep(oldObj[k])
        } else {
          // 否则属性值是基本数据类型,则直接赋值即可
          newObj[k] = oldObj[k]
        }
      }

      // 返回新对象
      return newObj
    }
    const newObj = cloneDeep(obj)
    newObj.family.father = 'dad'
    console.log(newObj)
    console.log(obj)

  </script>
</body>

</html>

241121

7. 案例5_购物车

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
  <link rel="stylesheet" href="./css/car.css">
</head>

<body>
  <div class="list">
    <div class="item">
      <img src="https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg" alt="">
      <p class="name">称心如意手摇咖啡磨豆机咖啡豆研磨机 <span class="tag">【赠品】10优惠券</span> <span class="time">2022/8/20</span>
      </p>
      <p class="spec">白色/10寸</p>
      <p class="price">289.90</p>
      <p class="count">x2</p>
      <p class="sub-total">579.80</p>
    </div>
  </div>
  <div class="total">
    <div>
      合计:
      <span class="amount">1000.00</span>
    </div>
  </div>
  <script>
    const goodsList = [
      {
        id: '4001172',
        name: '称心如意手摇咖啡磨豆机咖啡豆研磨机',
        price: 289.9,
        picture:
          'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg',
        count: 2,
        spec: { color: '白色' },
      },
      {
        id: '4001009',
        name: '竹制干泡茶盘正方形沥水茶台品茶盘',
        price: 109.8,
        picture:
          'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png',
        count: 3,
        spec: { size: '40cm*40cm', color: '黑色' },
      },
      {
        id: '4001874',
        name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器',
        price: 488,
        picture:
          'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png',
        count: 1,
        spec: { color: '青色', sum: '一大四小' },
        gift: '500g茶叶,羽毛球',
      },
      {
        id: '4001649',
        name: '大师监制龙泉青瓷茶叶罐',
        price: 139,
        picture:
          'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png',
        count: 2,
        spec: { size: '小号', color: '紫色' },
        gift: '50g茶叶,清洗球',
      },
    ]

    render(goodsList)
    function render(data) {
      const str = data.map(el => {
        const { name, price, picture, count, spec, gift } = el
        // const { size, color } = spec
        const specStr = Object.values(spec).join('/')

        // console.log(gift?.split(','))
        const giftStr = gift
          ? gift.split(',').map(el => `<span class="tag">【赠品】${el}</span>`).join('')
          : ''
        return `
          <div class="item">
            <img src="${picture}" alt="">
            <p class="name">${name} ${giftStr} <span class="time">2022/8/20</span>
            </p>
            <p class="spec">${specStr}</p>
            <p class="price">${price.toFixed(2)}</p>
            <p class="count">x${count}</p>
            <p class="sub-total">${(price * count).toFixed(2)}</p>
          </div>
        `
      }).join('')
      document.querySelector('.list').innerHTML = str

      const allPrice = data.reduce((prev, current) => {
        return prev + current.count * current.price
      }, 0)
      document.querySelector('.amount').innerHTML = allPrice.toFixed(2)
    }
  </script>
</body>

</html>

8. 异常处理

8.1 throw 抛异常

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <!-- 异常处理是指预估代码执行过程中可能发生的错误,
   然后最大程度的避免错误的发生导致整个程序无法继续运行.
   
  了解 JavaScript 中程序异常处理的方法,提升代码运行的健壮性。
   -->

  <!-- 
    throw 抛异常
      1. throw 抛出异常信息,程序也会终止执行
      2. throw 后面跟的是错误提示信息
      3. Error 对象配合 throw 使用,能够设置更详细的错误信息
  -->
  <script>
    function fn(x, y) {
      if (!x || !y) {
        throw new Error('传入两个参数都不能为空')
      }
      console.log(x + y)
    }
    fn(1, 2)
    fn(1)

  </script>
</body>

</html>

8.2 try /catch 捕获异常

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <p>这是文字p</p>

  <!-- 
    try /catch 捕获异常
    try试试 catch拦住 finally最后
      1. 将预估可能发生错误的代码写在 try 代码段中
      2. 如果 try 代码段中出现错误后,会执行 catch 代码段,并截获到错误信息
      3. finally 不管是否有错误,都会执行
  -->
  <script>
    // 正确写法
    /* const p = document.querySelector('p')
    p.innerHTML = 'js' */

    /* const p = document.querySelector('.p')
    p.innerHTML = 'js' */

    try {
      const p = document.querySelector('p')
      // 可能出错的代码
      // const p = document.querySelector('.p')
      p.innerHTML = 'js'
    } catch (error) {
      console.log(error)
    } finally {
      console.log('finally不管是否有错误,都会执行')
    }

    console.log('1')

  </script>
</body>

</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值