JavaScript-Basic WebAPIs Day5 Notes

1、BOM和DOM的直观感受,培养直觉

BOM: Browser Object Model

DOM: Document Object Model

【很显然,BOM的范围要大于DOM】

 

 

2、为什么如下代码,最后控制台返回的结果是1 2 4 3而不是1 2 3 4?

  <script>
    console.log(1)
    console.log(2)
    setTimeout(function () {
      console.log(3)
    }, 0)
    console.log(4);
  </script>

这是因为JavaScript的事件循环机制(event loop)和异步操作(asynchronous operations)共同作用的结果。让我们逐步分析代码执行的过程:

  1. console.log(1):同步操作,立即执行,输出 1
  2. console.log(2):同步操作,立即执行,输出 2
  3. setTimeout(function () { console.log(3) }, 0)setTimeout 是一个异步操作,它将回调函数放入任务队列中,但不会立即执行。尽管延迟时间设置为 0 毫秒,JavaScript 依然需要等到当前的所有同步代码执行完毕后,才会处理任务队列中的回调函数。
  4. console.log(4):同步操作,立即执行,输出 4

此时,所有同步操作(console.log(1)console.log(2)console.log(4))已经执行完毕。JavaScript 会查看任务队列,发现有一个回调函数在 setTimeout 中被推入队列。然后异步任务开始执行,输出 3

执行顺序:

  1. 输出 1
  2. 输出 2
  3. 输出 4(同步操作先执行完)
  4. 输出 3(异步回调在同步代码执行完后才执行)

因此,最终控制台输出的顺序是 1 2 4 3

这种行为是因为 JavaScript 是单线程,它使用事件循环来处理异步操作。

 

3.追问:JavaScript 是单线程的? 难道JS没有和python一样的多进程、多线程编程吗?

JavaScript 确实是单线程的语言,意味着在主线程中,JavaScript 同时只能执行一个任务。这个设计的初衷是为了简化编程,避免多线程并发编程带来的复杂性,例如死锁、竞态条件等问题。

然而,JavaScript 通过事件循环机制异步编程模型来有效地处理并发任务,使得它在处理 I/O 操作、定时器、网络请求等非阻塞任务时,表现得像是“并行”执行。主要依靠的机制包括:

1. 事件循环(Event Loop)

JavaScript 的事件循环是其异步任务调度的核心。当执行异步操作(如 setTimeoutPromiseasync/await、网络请求)时,这些操作被放入任务队列,并在当前的所有同步任务执行完毕后,轮询任务队列执行相应的回调函数。

2. Web APIs 和任务队列

浏览器和 Node.js 提供了 Web APIs,比如 setTimeoutfetch、事件监听等,这些是异步调用的实现机制。JavaScript 把这些异步操作交给 Web API,Web API 会在任务完成后将回调函数放入任务队列中,等待事件循环来执行。

3. 异步模型

通过回调函数、Promise、async/await 等机制,JavaScript 可以高效地处理 I/O 密集型任务。这样,即便 JavaScript 是单线程的,它也不会因为等待某些任务(如网络请求)而阻塞整个程序的执行。

JavaScript 的并行处理:

虽然 JavaScript 本身的执行环境是单线程的,但在现代 JavaScript 中,也可以利用其他机制来进行并行处理:

1. Web Workers

Web Workers 是浏览器环境中提供的一种机制,允许在主线程之外启动多线程操作。通过 Workers,JavaScript 可以创建独立的线程来执行计算密集型任务,而不影响主线程的 UI 渲染和其他操作。

  • Web Workers 不能直接操作 DOM。
  • 主线程和 Worker 线程之间通过消息传递进行通信。

2. Node.js 中的 Worker Threads

在 Node.js 中,类似于浏览器中的 Web Workers,worker_threads 模块允许创建多线程,进行计算密集型任务,而不会阻塞主线程。

3. Cluster 模式(Node.js)

在 Node.js 中,除了多线程,你还可以使用 cluster 模块启动多进程来处理并发任务。每个进程都运行在独立的内存空间中,它们共享相同的服务器端口。适合处理高并发的服务器应用。

4. WebAssembly (WASM)

通过 WebAssembly,JavaScript 可以与其他编程语言(如 C、C++、Rust)交互,并进行并行计算。WebAssembly 提供了一种高效的方式来编写计算密集型的代码,并可以与 JavaScript 交互,从而实现类似多线程的性能。

 

 

4、为什么这个结果返回是true呢?

console.log(/^哈*$/.test('')) // true

让我们来分析正则表达式 /^哈*$/ 及其在 .test('') 上的行为。

1. 正则表达式 /^哈*$/

  • ^:表示匹配字符串的开始。
  • 哈*:表示匹配零个或多个 字符。
    • * 是量词,表示前面的字符()可以出现零次或多次
  • $:表示匹配字符串的结束。

2. .test('')

.test() 方法用于检测字符串是否匹配给定的正则表达式。返回 truefalse

3. 为什么会返回 true

  • 正则表达式中的 哈* 意思是:匹配零个或多个这意味着字符串可以包含任意数量的 ,包括零个
  • 当你传入空字符串 '' 时,哈* 允许匹配零个 ,所以空字符串是一个有效的匹配。
  • 因为 ^$ 分别匹配字符串的开始和结束,并且 哈* 允许出现零个 ,整个正则表达式成功匹配空字符串,所以返回 true

总结:

  • /^哈*$/ 匹配从开头到结尾包含零个或多个 的字符串。
  • 因为空字符串 '' 符合这个条件(包含零个 ),因此返回 true

如果你希望确保字符串至少包含一个 ,可以使用正则表达式 /^哈+$/,其中 + 表示至少出现一次。

 

5、如下代码,为什么css中的.error和.right在body里面找不到对应项,另外body标签里的this.value, value又是从何而来,怎么感觉这些不同的词总是没有事先声明然后不知道从哪里突然冒出来

<!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>
    <style>
        span {
            display: inline-block;
            width: 250px;
            height: 30px;
            vertical-align: middle;
            line-height: 30px;
            padding-left: 15px;
        }

        .error {
            color: red;
            background: url(./images/error1.png) no-repeat left center;
        } 

        .right {
            color: green;
            background: url(./images/right.png) no-repeat left center;
        }
    </style>
</head>

<body>
    <input type="text">
    <span></span>
    <script>
        // 1. 准备正则
        const reg = /^[a-zA-Z0-9-_]{6,16}$/
        const input = document.querySelector('input')
        const span = input.nextElementSibling
        input.addEventListener('blur', function () {
            // console.log(reg.test(this.value))
            if (reg.test(this.value)) {
                span.innerHTML = '输入正确'
                span.className = 'right'
            } else {
                span.innerHTML = '请输入6~16位的英文数字下划线'
                span.className = 'error'
            }
        }) 
    </script>
</body>

</html>

我们来逐步分析这个代码,尤其是你提到的几个疑惑点。

1. 为什么 CSS 中的 .error.right 在 body 中找不到?

这其实是因为 .error.right动态添加<span> 元素上的。

你在 HTML 的 <body> 中并没有事先给任何元素加上 class="error"class="right"

而是通过 JavaScript 事件处理器在用户与 <input> 交互(即当用户“失去焦点”时)后,动态修改了 <span>className

解释过程:

  • CSS 中定义了 .error.right 两个类,分别为 <span> 设置不同的样式(如红色或绿色文字)。
  • 这些类并没有直接在 HTML 结构中出现,而是在输入框 <input> 失去焦点(blur 事件)时,由 JavaScript 判断输入值是否合法,并为 <span> 动态添加这些类(span.className = 'right'span.className = 'error')。
  • 所以,在页面加载时你不会看到这些类被使用,只有在用户输入内容并触发 blur 事件后,才会根据验证结果动态添加相应的类到 <span>

2. this.value 是从哪里来的?

this.value 是 JavaScript 中的一个概念,和 this 的上下文有关。在事件处理函数(比如 input.addEventListener('blur', ...))中,this 通常指向触发事件的元素,也就是这里的 <input> 元素。

解释过程:

  • this 指向的是当前处理事件的对象。在这个例子中,blur 事件监听器中的 this 就是 <input> 元素。
  • <input> 元素有一个 value 属性,表示输入框中当前输入的值。通过 this.value,你可以获取到用户输入的内容。
  • blur 事件触发时,this.value 就是用户输入框中输入的文本,reg.test(this.value) 用于测试输入的值是否符合指定的正则表达式规则。

因此,this.value 实际上是动态获取用户输入的值,thisinputblur 事件中自动指向了那个 input 元素,value 则是用户在输入框中键入的内容。

3. 代码中动态类的作用

blur 事件触发后,JavaScript 会根据用户输入的内容执行以下逻辑:

  • 如果输入符合正则表达式 reg 的规则,span 元素的 className 被设置为 right,显示绿色文字,并且背景图为 right.png
  • 如果输入不符合规则,span 元素的 className 被设置为 error,显示红色文字,并且背景图为 error1.png

这个过程在浏览器上看起来就是,当用户在输入框输入文本并离开输入框时,右边的 span 文字会根据输入是否符合规则显示不同的提示信息,并且颜色和背景图片会根据 className 的变化发生相应的变化。

4. 总结:

  • .error.right 是通过 JavaScript 动态添加到 <span> 元素上的,而不是在页面加载时直接出现在 HTML 里。
  • this.value 是从事件处理器中的 this 指向的 <input> 元素那里来的,用于获取用户输入的值。

 

6、如下代码的正则表达式该如何理解?

  <script>
    console.log(/^java$/.test('java')) // true
    console.log(/^java$/i.test('JAVA')) // 
    console.log(/^java$/i.test('Java'))
    const str = 'java是一门编程语言, 学完JAVA工资很高'
    const re = str.replace(/java|JAVA/g, '前端')
    // const re = str.replace(/java/ig, '前端')
    console.log(re)  // 前端是一门编程语言, 学完前端工资很高
  </script>

让我们一步步分析代码及其输出,理解正则表达式的工作方式。

1. 正则表达式 /^java$/'java' 的匹配

解释:

  • 正则表达式 /^java$/

    • ^:匹配字符串的开始。
    • java:精确匹配 "java"
    • $:匹配字符串的结束。

    因此,这个正则表达式匹配的字符串必须是完全等于 "java",并且不能有其他字符。

  • 'java':正好匹配这个条件,所以返回 true

2. 正则表达式 /^java$/i'JAVA' 的匹配

console.log(/^java$/i.test('JAVA')) // true

解释:

  • 正则表达式 /^java$/i
    • /^java$/ 的意思与之前一样,精确匹配 "java"
    • i 修饰符:使正则表达式不区分大小写
  • 'JAVA':虽然是大写字母,但由于 i 修饰符使得正则表达式忽略大小写,所以 "JAVA" 也会被认为是 "java",因此返回 true

3. 正则表达式 /^java$/i'Java' 的匹配

console.log(/^java$/i.test('Java')) // true

解释:

  • 这里同样使用了 /^java$/i,因为正则表达式忽略大小写,因此 "Java" 也会匹配成功,返回 true

4. 字符串替换 str.replace(/java|JAVA/g, '前端')

const str = 'java是一门编程语言, 学完JAVA工资很高'
const re = str.replace(/java|JAVA/g, '前端')

解释:

  • str:原始字符串 "java是一门编程语言, 学完JAVA工资很高"

  • 正则表达式 /java|JAVA/g

    • java|JAVA:匹配 "java""JAVA"| 是“或”的意思。
    • g:全局修饰符,表示在整个字符串中查找所有匹配项,而不仅仅是第一个。

    该正则表达式会匹配 str 中的所有 "java""JAVA",然后将其替换为 "前端"

  • 替换后的结果:'前端是一门编程语言, 学完前端工资很高'

    正则表达式匹配到了两个地方的 "java""JAVA",并将它们都替换成了 "前端",输出为:

console.log(re)  // 前端是一门编程语言, 学完前端工资很高

5. 替代方案:/java/ig

你还注释掉了一行代码:

// const re = str.replace(/java/ig, '前端')

解释:

  • 正则表达式 /java/ig
    • java:匹配 "java"
    • i:不区分大小写。
    • g:全局匹配所有的 "java",包括大小写不敏感的 "java""JAVA"

使用 /java/ig/java|JAVA/g 的效果是相同的,因为 /java/ig 通过 i 修饰符忽略大小写,匹配到了 "java""JAVA",然后替换成 "前端"

因此,结果也是:

console.log(re) // 前端是一门编程语言, 学完前端工资很高

总结:

  • /^java$/i 使得正则表达式忽略大小写,因此 "java""JAVA""Java" 都会匹配。
  • 正则表达式 /java|JAVA/g/java/ig 用来在字符串中全局替换 "java""JAVA",将它们替换为 "前端"

 

7、对于change这个触发动作,我理解像click, scroll,这些动作等也都是发生了change, 为什么不统一用change来代替呢?change的作用范围触发时机又是什么呢?

<!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>
</head>

<body>
  <!-- <input type="text"> -->
  <input type="checkbox" name="" id="">
  <script>
    // change 事件 内容发生了变化
    const input = document.querySelector('input')
    input.addEventListener('change', function () {
      console.log(111)
    })
  </script>
</body> 

</html>

JavaScript 中的 change 事件和 clickscroll 等事件各自有不同的用途和作用范围。它们被设计为处理不同类型的用户交互,虽然表面上它们都可能导致页面的一些“变化”,但每个事件的触发时机和用途有所不同。

1. change 事件的作用范围

change 事件主要用于表单元素(如 <input><select><textarea> 等)上,表示元素的发生了变化。

触发条件:

  • 对于 <input type="text"><textarea>:当用户在输入框中输入内容并失去焦点时(即用户点击或切换到其他元素后),触发 change 事件。
  • 对于 <input type="checkbox"><input type="radio">:当用户勾选或取消勾选时立即触发 change 事件。
  • 对于 <select>:当用户从下拉列表中选择一个不同的选项时,触发 change 事件。

例子:

<input type="text" placeholder="输入文本">
<input type="checkbox">
<select>
  <option value="1">选项1</option>
  <option value="2">选项2</option>
</select>
<script>
  const textInput = document.querySelector('input[type="text"]');
  const checkbox = document.querySelector('input[type="checkbox"]');
  const select = document.querySelector('select');

  textInput.addEventListener('change', () => console.log('Text input changed!'));
  checkbox.addEventListener('change', () => console.log('Checkbox changed!'));
  select.addEventListener('change', () => console.log('Select changed!'));
</script>

在上面的代码中,change 事件仅在输入或选项的值真正改变时才会触发。

2. 为什么不能统一用 change

clickscroll 等事件虽然也会引起页面的一些变化,但它们代表的并不是值的变化而是用户的特定动作:【换言之,change不涉及动作的change, 而是的change】

  • click:表示用户点击了某个元素。它跟用户值的改变无关,可能只是触发了一个按钮或者某个链接的行为。
  • scroll:表示用户滚动了页面或某个可滚动的元素。
  • input:表示用户在输入框中每次输入时就触发,而不需要等待焦点离开。

3. change 与其他事件的区别

事件描述典型应用
change 只会在用户完成输入或操作并改变了值时触发 处理表单元素的值变化,例如文本框、下拉菜单、复选框
click 当用户点击某个元素时立即触发 处理按钮点击、链接点击等事件
input 在用户每次输入时触发,无需等待用户失去焦点 实时监听用户在文本框中输入的内容
scroll 当用户滚动页面或某个可滚动元素时触发 处理页面滚动条滚动的事件

4. changeinput 的区别

对于 <input type="text">change 事件和 input 事件有不同的触发时机:

  • change:在输入框的内容改变并且失去焦点时触发。
  • input:每次输入时就立即触发,无需失去焦点。

例子:

<input type="text" placeholder="输入文本">
<script>
  const input = document.querySelector('input');
  
  input.addEventListener('change', () => console.log('Change event triggered'));
  input.addEventListener('input', () => console.log('Input event triggered'));
</script>

在这个例子中,input 事件会在用户每次输入时触发,而 change 事件只会在用户完成输入并且失去焦点后触发。

5. 总结

  • change 事件用于表单元素值的改变,比如文本框、复选框、单选按钮、下拉菜单等。
  • clickscroll 等事件表示用户的交互动作,它们并不表示值的变化,因此不能用 change 事件替代。
  • 统一使用 change 并不合理,因为每个事件处理的是不同类型的用户交互,针对不同场景。

 

8、select和radio这个两个标签的常见用法举例

1. <select> 简单用法

<select> 标签用于创建下拉菜单,里面包含多个 <option> 元素供用户选择。

<select name="choices" id="select-id">
  <option value="1">Option 1</option>
  <option value="2" selected>Option 2</option>  // selected 这个是默认选哪项的意思
  <option value="3">Option 3</option>
</select>

2. <input type="radio"> 简单用法

<input type="radio"> 创建单选按钮组,通常多个 <input type="radio"> 元素具有相同的 name,以确保它们是一个组。

<input type="radio" name="gender" value="male" id="male">  
<label for="male">Male</label>  // for的取值是来源于vlaue还是id?

<input type="radio" name="gender" value="female" id="female">
<label for="female">Female</label>

简要说明

  • <select> 创建的是一个下拉菜单。
  • <input type="radio"> 创建的是单选按钮,多个单选按钮可以形成一个选项组。

 

追问: 在上面展示的例子中,for的取值是来源于vlaue还是id?

<input type="radio" name="gender" value="male" id="male">  
<label for="male">Male</label>  // for的取值是来源于vlaue还是id?

<input type="radio" name="gender" value="female" id="female">
<label for="female">Female</label>

在以上代码中,<label> 标签中的 for="male"for="female" 的取值来源于相应的 id 属性,而不是 value 属性。

具体来说:

  • label 标签的 for 属性用于将标签与表单控件(如 <input>)关联起来。当用户点击 <label> 标签时,相应的表单控件(如对应的单选按钮)就会被选中。
  • for="male" 会将这个 <label> 标签与 id="male"<input> 元素关联起来。
  • for="female" 会将这个 <label> 标签与 id="female"<input> 元素关联起来。

解释:

  • id 属性用于唯一标识页面中的元素,for 属性的值必须与目标控件的 id 相同,才能建立关联。
  • value 属性则表示当这个 <input> 被选中时传递的值,它不用于 <label> 的关联。

示例代码解释:

<input type="radio" name="gender" value="male" id="male">
<label for="male">Male</label>

<input type="radio" name="gender" value="female" id="female">
<label for="female">Female</label>
  • 当用户点击 “Male” 的 <label>,由于 for="male"id="male" 匹配,所以 id="male" 的单选按钮会被选中。
  • 当用户点击 “Female” 的 <label>,由于 for="female"id="female" 匹配,所以 id="female" 的单选按钮会被选中。

总结:

  • for 属性的值 来源于对应表单控件的 id 属性,而不是 value

 

9、raido和check有何异同?

<input type="radio"><input type="checkbox"> 都是 HTML 中的表单控件,用于接受用户输入。它们的主要相似点和区别如下:

相似点

  1. 表单元素:两者都是表单控件,用户可以用来选择选项。
  2. 事件监听:两者都可以使用 JavaScript 的 changeclick 事件来监听用户的交互。
  3. 标签可以使用 <label> 标签与它们关联,这样点击文本也可以选择选项。

区别

特性<input type="radio"><input type="checkbox">
多选情况 同一组内的单选按钮只能选择一个。 可以选择多个选项,即同一组内可以多选。
组行为 一组单选按钮具有相同的 name 属性,确保只能选择一个。 每个复选框独立工作,不受其他复选框影响。
默认选中 一个组中只能有一个被选中。 可以没有选中项,也可以有多个项被选中。
视觉差异 显示为圆形,选中时内部填满圆点。 显示为方框,选中时内部打勾。
用例 适合用户在一组互斥的选项中进行单一选择。 适合用户在多个选项中进行多选。

示例代码

单选按钮 (radio):

<p>Gender:</p>
<input type="radio" name="gender" value="male" id="male">
<label for="male">Male</label>

<input type="radio" name="gender" value="female" id="female">
<label for="female">Female</label>
  • 这里的 name="gender" 确保在这两个选项中只能选择一个。

复选框 (checkbox):

<p>Hobbies:</p>
<input type="checkbox" name="hobby" value="reading" id="reading">
<label for="reading">Reading</label>

<input type="checkbox" name="hobby" value="sports" id="sports">
<label for="sports">Sports</label>

<input type="checkbox" name="hobby" value="music" id="music">
<label for="music">Music</label>
  • 复选框允许用户在多个选项中选择一个或多个。

总结

  • radio:用于一组中只能选择一个的情况。
  • checkbox:用于允许多选的情况。

 

 

posted @ 2024-09-13 23:39  AlphaGeek  阅读(9)  评论(0)    收藏  举报