Web APIs 核心知识(5)
BOM 操作
1. JS 组成
JavaScript 的核心是 ECMAScript,但它也包括了文档对象模型 (DOM) 和浏览器对象模型 (BOM)。BOM 提供了与浏览器进行交互的 API,这使得 JavaScript 可以控制浏览器窗口和框架。
2. Window 对象
Window 对象是所有浏览器对象的全局对象,所有的 BOM 对象都是它的属性和方法。以下是一些常用的 Window 对象方法和属性:
// 弹出警告框
window.alert('Hello, World!');
// 打开一个新的浏览器窗口
let newWindow = window.open('https://www.example.com', '_blank');
// 关闭浏览器窗口
newWindow.close();
// 获取窗口的宽度和高度
let width = window.innerWidth;
let height = window.innerHeight;
console.log(`Width: ${width}, Height: ${height}`);
3. 定时器延迟函数
JavaScript 提供了两种定时器函数:setTimeout
和 setInterval
。
// setTimeout:在指定时间后执行一次
setTimeout(() => {
console.log('This message is shown after 3 seconds');
}, 3000);
// setInterval:每隔指定时间执行一次
let intervalId = setInterval(() => {
console.log('This message is shown every 2 seconds');
}, 2000);
// 清除定时器
setTimeout(() => {
clearInterval(intervalId);
}, 10000);
4. JS执行机制
JavaScript 的执行机制主要围绕着事件循环(Event Loop)展开。理解 JavaScript 的执行机制需要掌握以下几个概念:
- 单线程:JavaScript 是单线程语言,即同一时间只能执行一段代码。
- 调用栈:调用栈(Call Stack)是一个 LIFO(Last In, First Out)结构,用于存储函数调用的执行顺序。
- 任务队列:任务队列(Task Queue)用于存储等待执行的任务,这些任务分为宏任务(Macro Task)和微任务(Micro Task)。
- 事件循环:事件循环(Event Loop)是 JavaScript 的执行模型,负责协调调用栈和任务队列,确保非阻塞异步执行。
4.1 调用栈
调用栈用于跟踪函数调用顺序,当一个函数被调用时,它会被压入调用栈,函数执行完后会从调用栈弹出。
function first() {
console.log("First");
second();
console.log("First End");
}
function second() {
console.log("Second");
}
first();
执行结果:
First
Second
First End
执行过程:
- 调用
first()
,first
压入调用栈。 - 打印
First
。 - 调用
second()
,second
压入调用栈。 - 打印
Second
,second
弹出调用栈。 - 打印
First End
,first
弹出调用栈。
4.2 任务队列和事件循环
任务队列包含两类任务:宏任务(例如 setTimeout
、setInterval
)和微任务(例如 Promise
、process.nextTick
)。事件循环不断检查调用栈是否为空,然后处理任务队列中的任务。
console.log("Start");
setTimeout(() => {
console.log("Timeout");
}, 0);
Promise.resolve().then(() => {
console.log("Promise");
});
console.log("End");
执行结果:
Start
End
Promise
Timeout
执行过程:
- 打印
Start
。 setTimeout
回调函数被添加到宏任务队列。Promise
回调函数被添加到微任务队列。- 打印
End
。 - 调用栈清空后,事件循环处理微任务队列,打印
Promise
。 - 最后处理宏任务队列,打印
Timeout
。
4.3 综合案例
下面是一个更复杂的例子,包含多个宏任务和微任务:
console.log("Script start");
setTimeout(() => {
console.log("SetTimeout 1");
}, 0);
Promise.resolve().then(() => {
console.log("Promise 1");
}).then(() => {
console.log("Promise 2");
});
setTimeout(() => {
console.log("SetTimeout 2");
}, 0);
console.log("Script end");
执行结果:
Script start
Script end
Promise 1
Promise 2
SetTimeout 1
SetTimeout 2
执行过程:
- 打印
Script start
。 setTimeout
回调函数(SetTimeout 1)被添加到宏任务队列。Promise
回调函数(Promise 1)被添加到微任务队列。- 打印
Script end
。 - 调用栈清空后,事件循环处理微任务队列,打印
Promise 1
。 Promise 2
回调函数被添加到微任务队列,打印Promise 2
。- 处理宏任务队列,打印
SetTimeout 1
。 - 最后处理第二个
setTimeout
回调函数(SetTimeout 2),打印SetTimeout 2
。
通过这个案例,我们可以清晰地看到 JavaScript 的事件循环机制是如何协调调用栈、宏任务和微任务的执行顺序的。
5. Location 对象
Location 对象包含当前 URL 的信息,并提供了一些方法来操作它。
// 获取当前 URL
console.log(window.location.href);
// 重定向到另一个页面
window.location.href = 'https://www.example.com';
// 重新加载页面
window.location.reload();
6. Navigator 对象
Navigator 对象包含了浏览器的详细信息。
// 获取浏览器的用户代理字符串
console.log(navigator.userAgent);
// 检查是否在线
console.log(`Online: ${navigator.onLine}`);
7. History 对象
History 对象允许操作浏览器的会话历史记录。
// 前往历史记录中的前一页
history.back();
// 前往历史记录中的后一页
history.forward();
// 前往历史记录中的特定页
history.go(-2);
8. 本地存储 (重点)
本地存储包括 localStorage
和 sessionStorage
,它们允许以键值对的形式存储数据。
8.1 localStorage (重点)
localStorage
是持久化存储,数据不会随浏览器关闭而消失。
// 存储数据
localStorage.setItem('username', 'JohnDoe');
// 读取数据
let username = localStorage.getItem('username');
console.log(username);
// 删除数据
localStorage.removeItem('username');
// 清空所有数据
localStorage.clear();
8.2 sessionStorage (了解)
sessionStorage
是会话存储,数据在页面会话结束时被清除。
// 存储数据
sessionStorage.setItem('sessionKey', 'sessionValue');
// 读取数据
let sessionValue = sessionStorage.getItem('sessionKey');
console.log(sessionValue);
// 删除数据
sessionStorage.removeItem('sessionKey');
// 清空所有数据
sessionStorage.clear();
8.3 localStorage 存储复杂数据类型
localStorage
只能存储字符串,如果需要存储对象或数组,可以使用 JSON 序列化和反序列化。
// 存储对象
let user = {
name: 'John',
age: 30
};
localStorage.setItem('user', JSON.stringify(user));
// 读取对象
let storedUser = JSON.parse(localStorage.getItem('user'));
console.log(storedUser);
9. 综合案例
我们将实现一个学生就业表,利用本地存储保存数据。
9.1 数组 map 方法
map
方法创建一个新数组,其结果是该数组中的每个元素调用一次提供的函数后的返回值。
let numbers = [1, 2, 3];
let doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6]
9.2 数组 join 方法
join
方法将数组的所有元素连接成一个字符串。
let elements = ['Fire', 'Wind', 'Rain'];
console.log(elements.join('-')); // "Fire-Wind-Rain"
学生就业表实现
<!DOCTYPE html>
<html>
<head>
<title>学生就业表</title>
</head>
<body>
<h1>学生就业表</h1>
<form id="employmentForm">
<input type="text" id="name" placeholder="姓名" required>
<input type="text" id="job" placeholder="就业岗位" required>
<button type="submit">提交</button>
</form>
<h2>学生列表</h2>
<ul id="studentList"></ul>
<script>
document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('employmentForm');
const studentList = document.getElementById('studentList');
const students = JSON.parse(localStorage.getItem('students')) || [];
const displayStudents = () => {
studentList.innerHTML = '';
students.map((student, index) => {
let li = document.createElement('li');
li.textContent = `姓名: ${student.name}, 就业岗位: ${student.job}`;
studentList.appendChild(li);
});
};
displayStudents();
form.addEventListener('submit', (event) => {
event.preventDefault();
const name = document.getElementById('name').value;
const job = document.getElementById('job').value;
students.push({ name, job });
localStorage.setItem('students', JSON.stringify(students));
displayStudents();
form.reset();
});
});
</script>
</body>
</html>
在这个综合案例中,我们创建了一个简单的 HTML 表单来输入学生的姓名和就业岗位,并使用 localStorage
来保存这些数据。通过使用数组的 map
方法,我们可以动态地显示学生列表。