JavaScript-Advanced Days2 Notes

1、toFixed()方法的作用

 const num = 12.1
 console.log(num.toFixed()) // 12 不填位数默认是返回整数,取整
 console.log(num.toFixed(2)) // 12.00

实际上这个方法就是固定保留小数的位数

 

 

2、数组的.reduce()方法,聚合方法

 const arr = [1, 2, 3]
 const re = arr.reduce((prev, item) => prev + item)
 console.log(re) 

记住这个.reduce()函数的各个参数含义即可

arr.reduce(function(累计值, 当前元素){}, 起始值)

 

 

3、如下代码,解释下.find()方法和every()方法

    const arr = [
      {
        name: '小米',
        price: 1999
      },
      {
        name: '华为',
        price: 3999
      },
    ] 


    // 1. find 查找
    const mi = arr.find(item => item.name === '小米')
    console.log(mi)
    // 2. every 每一个是否都符合条件,如果都符合返回 true ,否则返回false
    const arr1 = [10, 20, 30]
    const flag = arr1.every(item => item >= 20)
    console.log(flag)

这段代码展示了两个常用的数组方法:.find().every()。下面逐一解释它们的概念、作用,并举例说明。

1. .find() 方法

概念:

.find() 方法用于在数组中查找第一个符合条件的元素,并返回该元素。如果没有找到符合条件的元素,则返回 undefined

作用:

.find() 方法遍历数组中的每个元素,直到找到符合提供的回调函数条件的第一个元素,并返回这个元素。

举例说明:

在代码中,arr 是一个手机对象的数组,其中有 "小米" 和 "华为" 两个对象。我们想要找到名字是 "小米" 的手机。

const mi = arr.find(item => item.name === '小米');
console.log(mi);
  • 解释:.find() 会遍历 arr 数组中的每个对象,找到第一个 item.name 等于 '小米' 的对象。
  • 输出结果:{ name: '小米', price: 1999 }

注意: .find() 只返回找到的第一个符合条件的元素,即使有多个符合条件的元素,它也只会返回第一个。

2. .every() 方法

概念:

.every() 方法用于检查数组中的每一个元素是否都符合给定的条件。如果数组中的所有元素都满足条件,返回 true;如果有任何一个元素不满足条件,则返回 false

作用:

.every() 遍历数组中的每个元素,检查它是否满足条件,如果有任何一个不符合条件,检查会立即停止并返回 false。如果所有元素都符合条件,则返回 true

举例说明:

在代码中,arr1 是一个数字数组 [10, 20, 30],我们想检查数组中的每个数字是否都大于等于 20。

const flag = arr1.every(item => item >= 20);
console.log(flag);
  • 解释:.every() 会遍历 arr1 数组中的每个数字,检查它是否大于等于 20。
  • 在这个例子中,arr1 的第一个元素 10 不满足 item >= 20 的条件,因此 .every() 会立即返回 false
  • 输出结果:false

另一个例子:

假设我们改动一下数组,变成 [20, 30, 40],然后再运行 .every() 方法。

const arr2 = [20, 30, 40];
const flag = arr2.every(item => item >= 20);
console.log(flag);
  • 在这个例子中,所有元素都满足 item >= 20,所以 every() 返回 true
  • 输出结果:true

总结:

  • .find():查找数组中第一个符合条件的元素,并返回该元素。
  • .every():检查数组中的每一个元素是否都符合条件,全部符合返回 true,否则返回 false

补充

.every() 方法相对的是 .some() 方法,它可以用来判断数组中是否有任意一个元素符合条件。只要有一个元素满足条件,它就返回 true,如果所有元素都不满足条件,才返回 false

1. .some() 方法

概念:

.some() 方法用于检查数组中的任意一个元素是否符合给定的条件。如果有任何一个元素满足条件,则返回 true;如果所有元素都不满足条件,则返回 false

举例说明:

我们用一个例子来演示 .some() 的用法:

const arr = [10, 20, 30];

// 检查数组中是否有任意一个元素大于等于 20
const result = arr.some(item => item >= 20);
console.log(result); // 输出 true

在这个例子中,arr 数组的第二个元素 20 和第三个元素 30 都满足 item >= 20 的条件,所以 .some() 返回 true

另一个例子:

如果我们换一个数组来演示,当所有元素都不满足条件时,.some() 返回 false

const arr2 = [5, 10, 15];

// 检查是否有任意一个元素大于等于 20
const result2 = arr2.some(item => item >= 20);
console.log(result2); // 输出 false
  • 在这个例子中,数组 arr2 中的所有元素都小于 20,因此 .some() 返回 false

总结:

  • .every():检查数组中的每一个元素是否都符合条件,全部符合返回 true,否则返回 false
  • .some():检查数组中的任意一个元素是否符合条件,只要有一个符合就返回 true,如果所有元素都不符合则返回 false

.some().every() 可以说是互补的,一个是“任意符合”,另一个是“全部符合”。

 

4、关于.join()方法的作用体会。

其实类似python的 “ ”.join()方法,将列表连接成字符串

  <script>
    const spec = { size: '40cm*40cm', color: '黑色' }
    //1. 所有的属性值回去过来  数组
    console.log(Object.values(spec))
    // 2. 转换为字符串   数组join('/') 把数组根据分隔符转换为字符串
    console.log(Object.values(spec).join('/'))
    document.querySelector('div').innerHTML = Object.values(spec).join('/')
  </script> 

输出结果:

 

 

5、如何理解这里的把伪数组转化为真数组

在 JavaScript 中,伪数组(也叫类数组对象)是指那些具有数组类似结构的数据类型。它们通常拥有类似数组的 length 属性和按索引存取元素的能力,但它们不是 JavaScript 原生的数组对象,因此不能直接使用数组的方法(如 .pop().push() 等)。

伪数组的例子:

NodeListHTMLCollection 这样的 DOM 元素集合是常见的伪数组。它们可以通过索引访问元素,并且有 length 属性,但不能直接调用数组的方法。

具体场景:

在你的代码中,document.querySelectorAll('ul li') 返回的就是一个 NodeList,这是一个伪数组。我们可以像数组一样使用索引来获取其中的元素,也能知道它的长度,但它没有真正的数组方法。

const lis = document.querySelectorAll('ul li');
console.log(lis);  // NodeList(伪数组)

如果你尝试对这个伪数组使用数组的 .pop() 方法,会报错,因为 NodeList 并不继承数组的方法。

为什么要把伪数组转化为真数组?

为了能够使用数组的所有方法(如 .pop().map().filter() 等),你需要把伪数组转换为真数组。

如何转化?

可以使用 Array.from() 方法,它可以将伪数组或者可迭代对象转换为真正的数组。

const liss = Array.from(lis); // 将伪数组 lis 转换为真正的数组 liss

这样 liss 就是一个标准的数组了,你可以对它使用数组的方法,比如 .pop()

liss.pop(); // 现在可以使用数组方法
console.log(liss); // 输出的是真正的数组

总结:

  • 伪数组(如 NodeList)和真正的数组结构相似,但不能直接调用数组的方法。
  • Array.from() 方法可以把伪数组转化为真正的数组,之后你就可以使用数组的所有方法。
  • 转换后,可以使用 .pop() 等数组方法对元素进行操作。

举个简单的伪数组和真数组区别的例子:

const lis = document.querySelectorAll('ul li'); // 返回一个 NodeList(伪数组)
console.log(lis.pop()); // 报错,因为 NodeList 没有 pop 方法

const realArray = Array.from(lis); // 把 NodeList 转为真数组
console.log(realArray.pop()); // 可以成功移除最后一个元素

 

6、关于字符串的常见几个使用方法如下,.split(' , '),  .substring(), .startWith(), .includes() 要熟练掌握

这个和python的用法非常类似,迁移成本低。

  <script>
    // 1. split 把字符串 转换为 数组  和 join() 相反
    const str = 'pink,red'
    const arr = str.split(',')
    console.log(arr)

    const str1 = '2022-4-8'
    const arr1 = str1.split('-') 
    console.log(arr1)


    // 2. 字符串的截取   substring(开始的索引号[, 结束的索引号])
    // 2.1 如果省略 结束的索引号,默认取到最后
    // 2.2 结束的索引号不包含想要截取的部分
    const str = '今天又要做核酸了'
    console.log(str.substring(5, 7)) 


    // 3. startsWith 判断是不是以某个字符开头
    const str = 'pink老师上课中'
    console.log(str.startsWith('pink'))


    // 4. includes 判断某个字符是不是包含在一个字符串里面
    const str = '我是pink老师'
    console.log(str.includes('pink')) // true

  </script>

 

7、如下这个写法,为什么要先乘以100,然后再除以100呢?

    // 3. 合计模块
    const total = goodsList.reduce((prev, item) => prev + (item.price * 100 * item.count) / 100, 0)
    // console.log(total)
    document.querySelector('.amount').innerHTML = total.toFixed(2)

在这段代码中,item.price 是一个小数值,表示商品的价格。代码中先将价格乘以 100,再除以 100,其主要目的是为了避免 浮点数精度问题

背景:浮点数精度问题

JavaScript 使用的是 IEEE 754 双精度浮点数存储,某些小数值在计算时可能会出现不精确的结果。特别是在涉及加法或乘法时,浮点数会有精度损失。例如,像 0.1 + 0.2 这样的计算,预期结果是 0.3,但在 JavaScript 中得到的是 0.30000000000000004

乘以 100 再除以 100 的原因

通过将价格先乘以 100,可以将浮点数转换为整数,减少小数部分的计算误差。计算完成后再除以 100,就能恢复到正确的价格格式。

具体步骤:

  1. 乘以 100:将价格从小数转换为整数的形式,这样可以避免浮点数运算中的精度丢失。
  2. 计算价格乘以数量的总值:计算完商品的价格与数量后的总价,这时结果相对精确。
  3. 再除以 100:把之前放大的价格还原到原始小数的精度。

通过一个更复杂的例子来展示不乘以 100 和乘以 100 再除以 100这两种算法的区别。我们会使用浮点数的小数位来展示差异。

例子:价格为 0.1,数量为 3

情况 1:不乘以 100 直接计算

const goodsList = [
  { price: 0.1, count: 3 },
];

const total = goodsList.reduce((prev, item) => prev + item.price * item.count, 0);
console.log(total);  // 输出结果

计算过程

  • 价格为 0.1,数量为 3
    • 0.1 * 3 = 0.30000000000000004 (出现浮点数精度问题)

输出结果:

0.30000000000000004

由于浮点数精度问题,结果不是我们期望的 0.3,而是 0.30000000000000004

情况 2:乘以 100 再除以 100

const goodsList = [
  { price: 0.1, count: 3 },
];

const total = goodsList.reduce((prev, item) => prev + (item.price * 100 * item.count) / 100, 0);
console.log(total);  // 输出结果

计算过程

  • 价格为 0.1,数量为 3
    • 先乘以 1000.1 * 100 = 10
    • 再乘以数量:10 * 3 = 30
    • 最后再除以 10030 / 100 = 0.3

输出结果:

0.3

这次我们得到了正确的结果 0.3,没有出现浮点数精度问题。

总结:

  • 不乘以 100 的情况:因为 JavaScript 的浮点数精度问题,计算结果会出现多余的小数位,导致 0.1 * 3 变成了 0.30000000000000004
  • 乘以 100 再除以 100 的情况:通过将小数转换为整数后计算,再还原为小数,避免了浮点数计算误差,得到了正确的结果 0.3

这个例子清楚地展示了在处理小数点运算时,乘以 100 再除以 100 的方法可以避免精度问题,确保结果准确。

 

 8、为什么如下标签数据都要放到<form></form>表单里面呢?如果不放在<form></form>标签内又会如何呢?

个人理解:可以把<form></form>先简单当作容器理解。

<!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>
</head>
<body>
  <h1>注册信息</h1>
  <form action="">
    <!-- 表单控件 -->
    <!-- 个人信息 -->
    <h2>个人信息</h2>
    <label>姓名:</label><input type="text" placeholder="请输入真实姓名">
    <br><br>
    <label>密码:</label><input type="password" placeholder="请输入密码">
    <br><br>
    <label>确认密码:</label><input type="password" placeholder="请输入确认密码">
    <br><br>
    <label>性别:</label>
    <label><input type="radio" name="gender"></label>
    <label><input type="radio" name="gender" checked></label>
    <br><br>
    <label>居住城市:</label>
    <select>
      <option>北京</option>
      <option>上海</option>
      <option>广州</option>
      <option>深圳</option>
      <option>武汉</option>
    </select>
    <!-- 教育经历 -->
    <h2>教育经历</h2>
    <label>最高学历:</label>
    <select>
      <option>博士</option>
      <option>硕士</option>
      <option>本科</option>
      <option>大专</option>
    </select>
    <br><br>
    <label>学校名称:</label><input type="text">
    <br><br>
    <label>所学专业:</label><input type="text">
    <br><br>
    <label>在校时间:</label>
    <select>
      <option>2015</option>
      <option>2016</option>
      <option>2017</option>
      <option>2018</option>
    </select>
    --
    <select>
      <option>2019</option>
      <option>2020</option>
      <option>2021</option>
      <option>2022</option>
    </select>
    <!-- 工作经历 -->
    <h2>工作经历</h2>
    <label>公司名称:</label><input type="text">
    <br><br>
    <label>工作描述:</label>
    <br>
    <textarea></textarea>
    <br><br>
    <!-- 协议 和 按钮 -->
    <input type="checkbox"><label>已阅读并同意以下协议:</label>
    <ul>
      <li><a href="#">《用户服务协议》</a></li>
      <li><a href="#">《隐私政策》</a></li>
    </ul>
    <br><br>
    <button>免费注册</button>
    <button type="reset">重新填写</button>
  </form>
</body>
</html>

在HTML中,将表单控件放在<form>标签内的主要原因是为了收集用户输入并将其提交到服务器。

<form>标签定义了表单的边界,包含了所有相关的输入控件,确保在提交时,所有的输入数据可以通过指定的action属性发送到服务器。

这样做不仅能提高数据的组织性,也便于实现表单验证和处理提交结果。

如果不将表单控件放在<form>标签内,以下情况会发生:

  1. 无法提交数据:用户输入的数据无法被收集和提交到服务器。<form>标签的存在是为了定义提交的上下文,缺少它,浏览器就无法理解哪些数据是属于同一个表单的。

  2. 无效的输入处理:表单验证和处理(如必填字段的检查)将无法正常工作。许多JavaScript库和浏览器本身的验证功能依赖于表单元素的结构。

  3. 缺乏组织性:不使用<form>标签会导致代码结构混乱,难以管理和理解。对于复杂的表单,缺少容器可能会使得维护和修改变得更加困难。

  4. 默认行为丧失:一些输入控件(例如提交按钮)在<form>中有特定的默认行为(如提交表单),如果不在<form>内,这些行为将无法正常触发。

总之,使用<form>标签是实现交互式用户输入的标准做法,缺少它会导致功能上的缺失和用户体验的降低。

 

 

 

 

 

posted @ 2024-09-16 15:49  AlphaGeek  阅读(11)  评论(0)    收藏  举报