当前位置: 首页 > news >正文

第三部分:赋予网页灵魂 —— JavaScript(下)

目录

  • 7 DOM 操作:控制网页的"智能面板
    • 7.1 小例子:点击按钮时改变段落文字,根据用户输入改变图片
    • 7.2 练习:实现一个简单的 Tab 切换效果
  • 8 事件处理:响应用户的"指令"
    • 8.1 小例子:实现点击按钮弹出提示框,监听输入框内容变化
    • 8.2 练习:制作一个可拖拽的方块
  • 9 异步编程:处理耗时任务的"预约"机制
    • 9.1 小例子:使用 setTimeout 模拟异步,Promise 封装,async/await 调用
    • 9.2 练习
  • 10 与服务器通信:Fetch API - 获取外部数据的"遥控器
    • 10.1 小例子:从 JSONPlaceholder (一个免费的假 API 服务) 获取用户数据并展示
    • 10.2 练习:创建一个简单的天气查询应用
  • 11 本地存储:浏览器的"小抽屉"
    • 11.1 小例子:实现一个记住用户偏好(如主题颜色)的功能
    • 11.2 练习
  • 12 ES6+ 新特性选讲:现代 JavaScript 的便捷写法
    • 12.1 小例子:演示各种新特性的用法
    • 12.2 练习
  • 阶段项目 3:打造你的第一个交互式应用
  • 结语

7 DOM 操作:控制网页的"智能面板

DOM 是浏览器将 HTML 文档解析成的一个树状结构模型,JavaScript 可以通过操作这个 DOM 树来动态地修改网页的内容、结构和样式。就像智能家居的中控面板,你可以通过它控制家里的所有设备(HTML 元素)。

获取元素: 是 DOM 操作的第一步,找到你要控制的那个"设备"。

  • getElementById: 通过 ID 获取唯一元素 (最快)。
  • getElementsByTagName/ClassName: 获取符合条件的元素集合 。
  • querySelector: 使用 CSS 选择器语法获取第一个匹配的元素 (非常强大常用)。
  • querySelectorAll: 使用 CSS 选择器语法获取所有匹配的元素集合 。
  • 修改内容: innerHTML (解析 HTML 标签), innerText (只获取/设置可见文本,受 CSS 影响), textContent (获取/设置所有文本内容,包括隐藏的,性能较好)。注意 innerHTML 的安全风险 (可能导致 XSS 攻击),如果只是设置文本,优先使用 textContent。
  • 修改属性: 直接用点号访问标准属性 (img.src = ‘new.jpg’),或用 setAttribute/getAttribute 处理标准和自定义属性。
  • 修改样式:
    • element.style.propertyName: 直接修改内联样式 (如 el.style.color = ‘red’),propertyName 是 CSS 属性的驼峰命名 (如 backgroundColor)。适合少量动态修改。
    • element.classList: 推荐的方式!通过添加/删除预定义的 CSS 类来改变样式,实现样式与行为分离。add(), remove(), toggle() (切换), contains() (检查)。
  • 创建/插入/删除: 动态地添加或移除页面元素。createElement 创建新标签,createTextNode 创建文本节点,appendChild 在末尾添加子节点,insertBefore 在指定子节点前插入,removeChild 删除子节点。

7.1 小例子:点击按钮时改变段落文字,根据用户输入改变图片

HTML (dom.html):

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>DOM 操作示例</title><style>.highlight { background-color: yellow; font-weight: bold; }.hidden { display: none; }</style>
</head>
<body><h1 id="main-title">DOM 操作</h1><p id="text-to-change">这是初始文本。</p><button id="change-text-btn">改变文本</button><button id="toggle-style-btn">切换样式</button><hr><img id="my-image" src="https://placehold.co/200x100/007bff/ffffff?text=Image+1" alt="占位图" width="200"><br><input type="text" id="image-url-input" placeholder="输入新图片 URL"><button id="change-image-btn">改变图片</button><hr><div id="container"><p>第一个子元素</p></div><button id="add-element-btn">添加元素</button><button id="remove-element-btn">移除最后一个元素</button><script src="dom_script.js"></script>
</body>
</html>

JavaScript (dom_script.js):

// --- 获取元素 ---
const titleElement = document.getElementById('main-title');
const textElement = document.getElementById('text-to-change');
const changeTextBtn = document.getElementById('change-text-btn');
const toggleStyleBtn = document.getElementById('toggle-style-btn');
const myImage = document.getElementById('my-image');
const imageUrlInput = document.getElementById('image-url-input');
const changeImageBtn = document.getElementById('change-image-btn');
const container = document.getElementById('container');
const addBtn = document.getElementById('add-element-btn');
const removeBtn = document.getElementById('remove-element-btn');// --- 修改内容和样式 ---
changeTextBtn.onclick = function() { // 简单的事件处理 (后面会学 addEventListener)textElement.textContent = "文本已被 JavaScript 改变!";
};toggleStyleBtn.onclick = function() {// 使用 classList.toggle() 切换类textElement.classList.toggle('highlight');// 或者直接修改 style (不推荐大量使用)// if (textElement.style.color === 'red') {//   textElement.style.color = 'black';// } else {//   textElement.style.color = 'red';// }
};// --- 修改属性 ---
changeImageBtn.onclick = function() {const newImageUrl = imageUrlInput.value; // 获取输入框的值if (newImageUrl) { // 检查是否有输入myImage.src = newImageUrl;myImage.alt = "用户提供的新图片"; // 同时更新 alt 文本imageUrlInput.value = ''; // 清空输入框} else {alert("请输入图片 URL!");}
};
// 图片加载失败处理
myImage.onerror = function() {console.error("图片加载失败:", myImage.src);myImage.src = 'https://placehold.co/200x100/cccccc/ffffff?text=Image+Error'; // 替换为错误提示图myImage.alt = "图片加载失败";
};// --- 创建和插入/删除节点 ---
addBtn.onclick = function() {// 创建一个新的 <p> 元素const newParagraph = document.createElement('p');// 创建文本节点const newText = document.createTextNode(`这是新添加的元素 #${container.children.length + 1}`);// 将文本节点添加到 p 元素中newParagraph.appendChild(newText);// 将新的 p 元素添加到 container 的末尾container.appendChild(newParagraph);
};removeBtn.onclick = function() {const lastElement = container.lastElementChild; // 获取最后一个子元素if (lastElement) { // 确保有子元素可移除container.removeChild(lastElement);} else {console.log("容器内没有元素可以移除了。");}
};

运行后的效果
在这里插入图片描述

7.2 练习:实现一个简单的 Tab 切换效果

  • HTML 结构:包含几个 Tab 按钮和一个内容区域,内容区域包含几个 div,每个 div 对应一个 Tab 的内容,初始时只有一个 div 显示,其他隐藏。
  • JavaScript 逻辑:点击某个 Tab 按钮时,将所有内容 div 隐藏,然后只显示与被点击 Tab 对应的那个 div。同时,可以给当前激活的 Tab 按钮添加一个特殊的 CSS 类(例如 active)来高亮显示。

8 事件处理:响应用户的"指令"

事件处理让 JavaScript 能够响应用户的各种操作(点击、移动鼠标、敲击键盘、提交表单等)或浏览器的状态变化(页面加载完成、窗口大小改变等)。就像给智能家居系统添加传感器和响应规则:“当检测到有人按下门铃 (事件),就播放提示音 (处理函数)”。

  • 事件监听器 (addEventListener): 推荐的绑定事件的方式。可以为一个事件绑定多个处理函数,更灵活。
    • type: 事件类型字符串 (如 ‘click’, ‘mouseover’)。
    • listener: 事件触发时要执行的函数(事件处理函数/回调函数)。
    • options: 可选参数对象,如 { capture: true } (使用捕获阶段), { once: true } (只触发一次)。
  • 事件对象 (event): 当事件触发时,浏览器会自动创建一个包含事件信息的对象,并将其作为参数传递给事件处理函数。你可以通过它获取鼠标位置 (event.clientX, event.clientY)、按下的键 (event.key)、目标元素 (event.target) 等信息。
  • event.preventDefault(): 阻止事件的默认行为。例如,阻止链接 (<a>) 的跳转,阻止表单 (<form>) 的默认提交。
  • event.stopPropagation(): 阻止事件在 DOM 树中继续传播(通常是阻止冒泡)。
  • 事件委托 (Event Delegation): 一个重要的性能优化技巧。将事件监听器添加到父元素上,利用事件冒泡来处理所有子元素的事件。特别适用于列表项很多或动态添加/删除子元素的情况。

8.1 小例子:实现点击按钮弹出提示框,监听输入框内容变化

HTML (event.html):

<!DOCTYPE html>
<html lang="zh-CN">
<head> <meta charset="UTF-8"> <title>事件处理</title> </head>
<body><button id="alert-btn">点我弹框</button><hr><label for="my-input">输入内容:</label><input type="text" id="my-input"><p>你输入了: <span id="output-span"></span></p><hr><a id="prevent-link" href="https://example.com">阻止默认跳转的链接</a><hr><div id="parent-div" style="padding: 20px; border: 1px solid blue;">父元素<button id="child-btn" style="margin-left: 10px;">子元素按钮</button></div><script src="event_script.js"></script>
</body>
</html>

JavaScript (event_script.js):

const alertBtn = document.getElementById('alert-btn');
const myInput = document.getElementById('my-input');
const outputSpan = document.getElementById('output-span');
const preventLink = document.getElementById('prevent-link');
const parentDiv = document.getElementById('parent-div');
const childBtn = document.getElementById('child-btn');// --- 基本事件监听 ---
alertBtn.addEventListener('click', function(event) {// event 对象包含了事件信息console.log('事件类型:', event.type);console.log('目标元素:', event.target);alert('按钮被点击了!');
});// 监听输入框的 'input' 事件 (内容实时变化时触发)
myInput.addEventListener('input', function(event) {outputSpan.textContent = event.target.value; // 将输入内容显示到 span
});// --- 阻止默认行为 ---
preventLink.addEventListener('click', function(event) {event.preventDefault(); // 阻止链接跳转alert('链接的默认跳转行为已被阻止!');
});// --- 阻止事件传播 (冒泡) ---
parentDiv.addEventListener('click', function(event) {console.log('父元素 Div 被点击了!');
});childBtn.addEventListener('click', function(event) {console.log('子元素 Button 被点击了!');event.stopPropagation(); // 阻止事件冒泡到父元素alert('子按钮点击,事件传播已阻止。');
});// --- 页面加载事件 ---
// 当整个页面及所有资源 (图片、样式表等) 加载完成时触发
window.addEventListener('load', function() {console.log('页面及所有资源加载完成!');
});// 当 HTML 文档被完全加载和解析完成之后触发,无需等待样式表、图像等完全加载
document.addEventListener('DOMContentLoaded', function() {console.log('DOM 完全加载并解析完成!(通常在这里执行需要操作 DOM 的代码)');// 可以在这里安全地获取和操作 DOM 元素alertBtn.style.backgroundColor = 'lightblue';
});

执行后的效果
在这里插入图片描述

8.2 练习:制作一个可拖拽的方块

  • HTML: 创建一个 div 作为可拖拽的方块。
  • CSS: 给方块设置 position: absolute; 或 relative; 使其可以定位。
  • JavaScript:
    • 监听方块的 mousedown 事件。
    • 在 mousedown 处理函数中,记录鼠标初始位置和方块初始位置,并添加对 document 的 mousemove 和 mouseup 事件监听。
    • 在 mousemove 处理函数中,计算鼠标移动的距离,并更新方块的 style.left 和 style.top 实现拖动。
    • 在 mouseup 处理函数中,移除对 document 的 mousemove 和 mouseup 事件监听,停止拖动。

9 异步编程:处理耗时任务的"预约"机制

JavaScript 默认是单线程的,意味着一次只能做一件事。同步代码按顺序执行,如果遇到耗时操作(如网络请求、大量计算),就会阻塞后续代码的执行,导致页面卡顿。异步编程就是解决这个问题的机制,它允许耗时任务在后台执行,完成后再通知主线程(通过回调、Promise 或 async/await),就像你去餐厅点餐(发起异步任务),然后可以先玩手机(执行其他代码),等餐好了(任务完成)服务员再叫你(执行回调)。

  • 回调函数: 最早的异步处理方式。将一个函数作为参数传递给异步函数,异步任务完成后调用该回调函数。缺点是如果多个异步任务有依赖关系,容易形成层层嵌套的"回调地狱 (Callback Hell)",代码难以阅读和维护。
  • Promise: ES6 引入,用于更好地管理异步操作。Promise 对象代表一个尚未完成但最终会完成(或失败)的操作。它有三种状态:pending (进行中)、fulfilled (已成功)、rejected (已失败)。
    • .then(onFulfilled, onRejected): 指定成功和失败状态的回调函数。可以链式调用 .then() 处理连续的异步操作。
    • .catch(onRejected): 专门用于捕获错误(等同于 .then(null, onRejected))。
    • .finally(onFinally): 无论成功或失败都会执行的回调。
    • Promise.all([p1, p2, …]): 等待所有 Promise 都成功后才成功,返回包含所有结果的数组;有一个失败则整体失败。
    • Promise.race([p1, p2, …]): 只要有一个 Promise 成功或失败,就立刻采用它的结果。
  • async/await: ES2017 引入,是基于 Promise 的语法糖,让异步代码看起来更像同步代码,更易读写。
    • async function: 在函数声明前加 async 关键字,表示该函数内部可以使用 await。async 函数总是返回一个 Promise。
    • await expression: 只能用在 async 函数内部,用于等待一个 Promise 完成,并返回其解决(fulfilled)的值。如果 Promise 被拒绝(rejected),await 会抛出错误,可以用 try…catch 捕获。

9.1 小例子:使用 setTimeout 模拟异步,Promise 封装,async/await 调用

console.log("同步代码 1");// 1. 使用 setTimeout 模拟异步 (回调函数)
setTimeout(function() {console.log("异步操作 1 (setTimeout) 完成");// 如果有后续依赖操作,需要嵌套在这里... Callback HellsetTimeout(function() {console.log("异步操作 2 (嵌套) 完成");}, 500);
}, 1000); // 1000毫秒 = 1秒 后执行console.log("同步代码 2");// 2. 使用 Promise 封装异步操作
function simulateAsync(message, delay) {return new Promise((resolve, reject) => {// 模拟成功或失败const success = Math.random() > 0.3; // 70% 概率成功setTimeout(() => {if (success) {console.log(`异步操作 (${message}) 完成`);resolve(`结果: ${message} 成功`); // 成功时调用 resolve} else {console.error(`异步操作 (${message}) 失败`);reject(new Error(`错误: ${message} 失败`)); // 失败时调用 reject}}, delay);});
}// 使用 Promise 处理链式异步
simulateAsync("任务A", 1500).then(resultA => {console.log(resultA);return simulateAsync("任务B", 500); // 返回新的 Promise 实现链式调用}).then(resultB => {console.log(resultB);console.log("Promise 链执行完毕");}).catch(error => { // 捕获链中任何一个环节的错误console.error("Promise 链中发生错误:", error.message);}).finally(() => {console.log("Promise 链最终清理工作");});// 3. 使用 async/await 简化 Promise 调用
async function runAsyncTaskSequence() {console.log("Async/Await: 开始执行异步序列");try {const result1 = await simulateAsync("任务X", 800);console.log("Async/Await:", result1);const result2 = await simulateAsync("任务Y", 600);console.log("Async/Await:", result2);console.log("Async/Await: 序列执行完毕");return "序列成功完成"; // async 函数返回 Promise} catch (error) {console.error("Async/Await: 序列中发生错误:", error.message);throw error; // 可以选择重新抛出错误} finally {console.log("Async/Await: 序列最终清理");}
}// 调用 async 函数
runAsyncTaskSequence().then(finalResult => console.log("Async 函数最终结果:", finalResult)).catch(finalError => console.error("Async 函数最终捕获错误:", finalError.message));console.log("同步代码 3 (可能在异步完成前执行)");

运行后的效果
在这里插入图片描述

9.2 练习

创建三个模拟异步任务的函数(使用 setTimeout 和 Promise),让它们按顺序执行(任务 2 在任务 1 成功后执行,任务 3 在任务 2 成功后执行),并使用 async/await 来实现。

10 与服务器通信:Fetch API - 获取外部数据的"遥控器

现代网页很少是完全静态的,它们需要从服务器获取最新数据(如新闻、商品列表)或向服务器提交用户数据(如表单信息)。Fetch API 是浏览器内置的、基于 Promise 的现代网络请求接口,就像一个可以远程控制服务器(获取信息或发送指令)的遥控器。

  • 基本用法: fetch(url) 默认发送 GET 请求。它返回一个 Promise,该 Promise resolve 为一个 Response 对象。
  • Response 对象: 代表服务器的响应。你需要调用它的方法(如 .json() 或 .text())来再次返回一个 Promise,这个 Promise 最终 resolve 为实际的数据。
  • 处理响应: 检查 response.ok (布尔值,表示 HTTP 状态码是否在 200-299 之间) 或 response.status 来判断请求是否成功。
  • 发送数据 (POST 等): 需要在 fetch 的第二个参数 options 对象中指定 method, headers, body。
    • method: ‘POST’, ‘PUT’, ‘DELETE’ 等。
    • headers: 通常需要设置 ‘Content-Type’ 来告诉服务器你发送的数据格式 (如 ‘application/json’)。使用 new Headers() 创建。
    • body: 要发送的数据。如果是 JSON,需要用 JSON.stringify() 转换成字符串。

10.1 小例子:从 JSONPlaceholder (一个免费的假 API 服务) 获取用户数据并展示

HTML (fetch.html):

<!DOCTYPE html>
<html lang="zh-CN">
<head> <meta charset="UTF-8"> <title>Fetch API 示例</title> </head>
<body><h1>用户列表</h1><button id="load-users-btn">加载用户数据</button><ul id="user-list"></ul><p id="loading-status"></p><script src="fetch_script.js"></script>
</body>
</html>

JavaScript (fetch_script.js):

const loadBtn = document.getElementById('load-users-btn');
const userList = document.getElementById('user-list');
const statusP = document.getElementById('loading-status');loadBtn.addEventListener('click', fetchUsers);async function fetchUsers() {statusP.textContent = '正在加载...';userList.innerHTML = ''; // 清空列表loadBtn.disabled = true; // 禁用按钮防止重复点击try {// 发送 GET 请求const response = await fetch('https://jsonplaceholder.typicode.com/users?_limit=5'); // 获取前 5 个用户console.log('Response Status:', response.status); // 打印状态码console.log('Response OK?', response.ok);      // 打印是否成功if (!response.ok) {// 如果 HTTP 状态码不是 2xx,抛出错误throw new Error(`HTTP 错误! 状态码: ${response.status}`);}// 解析 JSON 数据 (response.json() 返回 Promise)const users = await response.json();statusP.textContent = '加载成功!';// 将用户数据渲染到页面users.forEach(user => {const listItem = document.createElement('li');listItem.textContent = `ID: ${user.id}, 姓名: ${user.name}, 邮箱: ${user.email}`;userList.appendChild(listItem);});} catch (error) {// 捕获网络错误或解析错误console.error('获取用户数据失败:', error);statusP.textContent = `加载失败: ${error.message}`;} finally {loadBtn.disabled = false; // 无论成功失败,重新启用按钮}
}// 示例:发送 POST 请求 (需要后端支持)
async function postDataExample() {const dataToSend = { title: 'foo', body: 'bar', userId: 1 };try {const response = await fetch('https://jsonplaceholder.typicode.com/posts', {method: 'POST',headers: {'Content-Type': 'application/json; charset=UTF-8',},body: JSON.stringify(dataToSend), // 将 JS 对象转为 JSON 字符串});if (!response.ok) {throw new Error(`HTTP error! status: ${response.status}`);}const result = await response.json(); // 解析返回的 JSONconsole.log('POST 请求成功,服务器返回:', result);} catch (error) {console.error('POST 请求失败:', error);}
}
// postDataExample(); // 可以取消注释来尝试发送 POST 请求

运行后的效果
在这里插入图片描述

10.2 练习:创建一个简单的天气查询应用

  • HTML: 提供一个输入框让用户输入城市名,一个查询按钮,一个区域显示天气结果。
  • JavaScript:
    • 给按钮添加点击事件监听。
    • 在事件处理函数中,获取用户输入的城市名。
    • 使用 Fetch API 调用一个免费的天气 API (如 OpenWeatherMap - 可能需要注册获取 API Key,或者找一些无需 Key 的公共天气 API)。
    • 将城市名作为参数拼接到 API URL 中。
    • 处理 API 返回的 JSON 数据,提取需要的天气信息(如温度、天气描述、湿度等)。
    • 将天气信息显示在页面指定区域。
    • 添加适当的加载中和错误处理提示。

11 本地存储:浏览器的"小抽屉"

有时我们需要在用户关闭浏览器后仍然记住一些信息(如用户偏好、登录状态、未完成的表单),或者在单个会话期间临时存储数据。Web Storage API 提供了两个简单的机制:

  • localStorage: 持久化存储。数据会一直保留,除非用户手动清除浏览器缓存或代码主动删除。同源(协议、域名、端口相同)的所有页面共享 localStorage 数据。容量通常为 5-10MB。
  • sessionStorage: 会话级存储。数据只在当前浏览器标签页的生命周期内有效。关闭标签页或浏览器后,数据会被清除。不同标签页即使同源,sessionStorage 也不共享。容量与 localStorage 类似。

注意: 两者都只能存储字符串类型。存储对象或数组时,需要先用 JSON.stringify() 转换成 JSON 字符串,读取时再用 JSON.parse() 解析回来。它们是同步操作,不适合存储大量数据。

11.1 小例子:实现一个记住用户偏好(如主题颜色)的功能

HTML (storage.html):

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>本地存储示例</title><style>body.dark-theme { background-color: #333; color: white; }body.light-theme { background-color: #fff; color: black; }</style>
</head>
<body class="light-theme"> <h1>主题切换</h1><p>当前主题: <span id="theme-name">亮色</span></p><button id="toggle-theme-btn">切换主题</button><script src="storage_script.js"></script>
</body>
</html>

JavaScript (storage_script.js):

const toggleBtn = document.getElementById('toggle-theme-btn');
const themeNameSpan = document.getElementById('theme-name');
const body = document.body;// --- 应用存储的主题 ---
function applyTheme(theme) {if (theme === 'dark') {body.classList.remove('light-theme');body.classList.add('dark-theme');themeNameSpan.textContent = '暗色';} else {body.classList.remove('dark-theme');body.classList.add('light-theme');themeNameSpan.textContent = '亮色';}
}// --- 页面加载时读取 localStorage ---
// 使用 getItem 获取存储的主题,如果没有则默认为 'light'
let currentTheme = localStorage.getItem('theme') || 'light';
applyTheme(currentTheme);// --- 切换主题并存储 ---
toggleBtn.addEventListener('click', function() {// 切换主题逻辑if (currentTheme === 'light') {currentTheme = 'dark';} else {currentTheme = 'light';}// 应用新主题applyTheme(currentTheme);// 将新主题存储到 localStoragelocalStorage.setItem('theme', currentTheme);console.log(`主题已保存到 localStorage: ${currentTheme}`);// 示例:使用 sessionStorage (会话结束后清除)sessionStorage.setItem('lastAction', '切换主题');console.log('上次操作已存入 sessionStorage:', sessionStorage.getItem('lastAction'));
});// 清除示例 (通常不需要随便清除)
// localStorage.removeItem('theme');
// localStorage.clear(); // 清除所有 localStorage 数据
// sessionStorage.clear();

运行后的效果
在这里插入图片描述

11.2 练习

将你之前或现在实现的待办事项列表应用进行改进,将任务列表数据存储到 localStorage 中。

  • 当添加、删除、修改任务状态时,更新 localStorage 中的数据(记得将数组转换为 JSON 字符串)。
  • 当页面加载时,从 localStorage 读取数据(如果存在),解析 JSON 字符串,并根据这些数据重新渲染待办事项列表,这样即使用户刷新页面,任务也不会丢失。

12 ES6+ 新特性选讲:现代 JavaScript 的便捷写法

ECMAScript (ES) 是 JavaScript 的标准规范。ES6 (也叫 ES2015) 是一个重要的里程碑,引入了大量新特性,让 JavaScript 写起来更方便、更强大。后续版本 (ES7/ES2016, ES8/ES2017, …) 也在不断添加新功能。了解并使用这些新特性可以提高开发效率和代码质量。

  • 模板字符串: 使用反引号 ` 定义字符串,可以方便地嵌入变量 (${variable}) 和换行。
  • 解构赋值: 从数组或对象中提取值并赋给变量,语法更简洁。
  • 展开运算符: 将数组或对象"展开"成独立的元素或属性,常用于合并数组/对象、传递函数参数。
  • 剩余参数: 在函数定义时,将多余的参数收集到一个数组中。
  • 模块化: 将代码分割成独立的模块(文件),通过 export 导出需要暴露的部分,通过 import 导入其他模块的功能。这是构建大型应用的基础,有助于代码组织和复用。(浏览器原生支持需要 <script type="module">,或者通过 Webpack/Rollup 等构建工具处理)。

12.1 小例子:演示各种新特性的用法

// 1. 模板字符串
const userName = "Alice";
const userAge = 28;
const greeting = `你好,我是 ${userName},
我今年 ${userAge} 岁了。`; // 支持换行和变量嵌入
console.log(greeting);// 2. 解构赋值
// 数组解构
const numbers = [10, 20, 30];
const [first, second] = numbers;
console.log(first, second); // 输出: 10 20// 对象解构 (变量名需与属性名一致,或使用别名)
const person = { name: "Bob", city: "New York" };
const { name, city: personCity } = person; // city 重命名为 personCity
console.log(name, personCity); // 输出: Bob New York// 3. 展开运算符
// 合并数组
const arr1 = [1, 2];
const arr2 = [3, 4];
const combinedArr = [...arr1, 0, ...arr2, 5];
console.log(combinedArr); // 输出: [1, 2, 0, 3, 4, 5]// 合并对象 (ES2018)
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 }; // 相同属性会被后面的覆盖
const combinedObj = { ...obj1, ...obj2, d: 5 };
console.log(combinedObj); // 输出: { a: 1, b: 3, c: 4, d: 5 }// 函数参数传递
function sumNumbers(x, y, z) { return x + y + z; }
const numsToSum = [1, 2, 3];
console.log(sumNumbers(...numsToSum)); // 输出: 6// 4. 剩余参数
function logArgs(firstArg, ...restArgs) { // restArgs 是一个包含剩余参数的数组console.log("第一个参数:", firstArg);console.log("剩余参数:", restArgs);
}
logArgs('a', 'b', 'c', 'd');
// 输出:
// 第一个参数: a
// 剩余参数: [ 'b', 'c', 'd' ]// 5. 模块化 (基本概念 - 需要特定环境或构建工具)
// --- utils.js ---
// export const PI = 3.14;
// export function double(n) { return n * 2; }// --- main.js ---
// import { PI, double } from './utils.js';
// console.log(PI);
// console.log(double(5));

运行后的效果
在这里插入图片描述

12.2 练习

尝试使用 ES6+ 的语法(如箭头函数、模板字符串、解构赋值、let/const)来重构你之前编写的一些练习代码,体会语法的简洁性。

阶段项目 3:打造你的第一个交互式应用

理论学习完毕,是时候动手实践,将 HTML, CSS, JavaScript 结合起来,创建一个真正能与用户交互的前端应用了!

选择一个项目进行开发:

  1. 待办事项列表 (Todo List) 应用:

    • 核心功能: 添加新任务、将任务标记为已完成/未完成、删除任务、将任务列表存储到 localStorage 实现数据持久化。
    • 涉及技术: DOM 操作(创建列表项、修改样式)、事件处理(按钮点击、复选框状态改变)、数组操作、本地存储。
    • 挑战: 添加编辑任务功能、按完成状态过滤任务、设置任务优先级。
  2. 电影/图书搜索应用:

    • 核心功能: 提供输入框让用户搜索电影或图书名称,调用公共 API (如 The Movie Database (TMDb), Open Library API) 获取数据,将搜索结果(如海报、标题、简介)展示在页面上。
    • 涉及技术: DOM 操作(展示结果列表)、事件处理(搜索按钮点击、回车键搜索)、Fetch API、处理 JSON 数据、异步编程 (async/await)。
    • 挑战: 实现分页加载更多结果、点击结果项显示更详细信息、处理 API 请求错误。
  3. 简易计算器:

    • 核心功能: 实现一个基本的计算器界面,能够进行加、减、乘、除运算。
    • 涉及技术: DOM 操作(获取按钮点击、更新显示屏)、事件处理(数字和运算符按钮点击)、基本的算术逻辑处理、状态管理(记录当前数字、运算符、运算结果)。
    • 挑战: 实现更复杂的运算(如百分比、平方根)、处理连续运算、处理错误输入(如除以零)。

要求:

  • 项目包含清晰的 HTML 结构、合适的 CSS 样式和功能性的 JavaScript 代码。
  • JavaScript 代码应组织良好(例如,使用函数封装不同功能),并添加必要的注释。
  • 优先使用 addEventListener 绑定事件。
  • 优先使用 let/const 声明变量。
  • 考虑代码健壮性,进行适当的错误处理(如 API 请求失败、用户输入无效)。
  • (可选)尝试使用 ES6+ 新特性让代码更简洁。

这个阶段项目将是你综合运用前端三剑客(HTML, CSS, JS)能力的最好锻炼。放手去做吧!

结语

恭喜你,完成了 JavaScript 客户端部分的学习!你已经掌握了编程的基础语法、流程控制、数据结构(数组和对象),学会了如何通过 DOM 和事件让网页动起来、响应用户操作,了解了如何通过异步编程和 Fetch API 与服务器沟通,甚至接触了本地存储和现代 JS 特性。

现在,你的"房子"不仅有了结构和外观,还通上了"电",拥有了"智能系统",能够完成各种任务了!

JavaScript 的世界远不止于此,还有更多高级概念(如面向对象编程深入、设计模式、函数式编程、更复杂的 this 指向、性能优化等)和庞大的生态系统(各种框架、库、工具)等待你去探索。但你现在打下的基础,足以让你开始构建功能丰富的前端应用,并为后续学习 Node.js (后端) 和 React/Vue/Angular (前端框架) 做好准备。

最重要的仍然是:持续练习,不断实践! 尝试去实现你自己的想法,或者参与到开源项目中,在实践中巩固和深化你的 JavaScript 技能。

接下来,我们将继续学习javascript的强化版typescript

http://www.xdnf.cn/news/216631.html

相关文章:

  • Spring Boot - 配置管理与自动化配置进阶
  • 【Bash】可以请您解释性地说明一下“2>1”这个语法吗?
  • Windows 系统下使用 Docker 搭建Redis 集群(6 节点,带密码)
  • C++日更八股--first
  • SpringBoot应用:Docker与Kubernetes全栈实战秘籍
  • git fetch和git pull的区别
  • 域对齐是什么
  • 判断用户选择的Excel单元格区域是否跨页?
  • 力扣hot100——239.滑动窗口最大值
  • 在大数据环境下,使用spingboot为Android APP推送数据方案
  • 【Machine Learning Q and AI 读书笔记】- 02 自监督学习
  • 主流微前端框架比较
  • java面试题目
  • Nacos源码—2.Nacos服务注册发现分析四
  • 三种机器学习类型
  • Glide 如何加载远程 Base64 图片
  • MobileNetV2: 反向残差和线性瓶颈
  • 应急演练考试排查-DC01
  • 【动态导通电阻】GaN功率器件中动态导通电阻退化的机制、表征及建模方法
  • AI 的未来是开源?DeepSeek 正在书写新篇章!
  • 算法基础学习|02归并排序——分治
  • 封装js方法 构建树结构和扁平化树结构
  • 20_大模型微调和训练之-基于LLamaFactory+LoRA微调LLama3后格式合并
  • 水力压裂多裂缝扩展诱发光纤应变演化试验研究
  • 基于Mamba2的文本生成实战
  • 什么是 MCP?AI 应用的“USB-C”标准接口详解
  • AI赋能的问答系统:2025年API接口实战技巧
  • Vulkan与OpenGL的对比
  • 服务器主动发送响应?聊天模块如何实现?
  • 【Vue3/Typescript】合并多个pdf并预览打印,兼容低版本浏览器