JavaScript 教程¶
JavaScript 是一种动态、弱类型的编程语言,可以为网页添加交互性。本教程将带你学习 JavaScript 的核心概念和用法。
第一章:JavaScript 基础¶
(一)JavaScript 简介¶
什么是 JavaScript? JavaScript 是一种脚本语言,主要用于网页开发,可以为网页添加交互性和动态效果。
JavaScript 的特点: - 动态类型:变量无需声明类型 - 弱类型:自动类型转换 - 解释执行:由浏览器解释执行 - 事件驱动:响应用户操作 - 与 HTML 和 CSS 配合使用
(二)JavaScript 引入方式¶
内联 JavaScript:
内部 JavaScript:
外部 JavaScript:
第二章:JavaScript 语法¶
(一)变量和数据类型¶
// 变量声明
var name = "张三"; // 旧方式
let age = 20; // 推荐
const PI = 3.14159; // 常量
// 数据类型
let num = 123; // 数字
let str = "Hello"; // 字符串
let bool = true; // 布尔值
let arr = [1, 2, 3]; // 数组
let obj = {name: "张三"}; // 对象
let nothing = null; // 空值
let undefined; // 未定义
(二)运算符¶
// 算术运算符
let a = 10, b = 3;
console.log(a + b); // 13
console.log(a - b); // 7
console.log(a * b); // 30
console.log(a / b); // 3.333...
console.log(a % b); // 1
// 比较运算符
console.log(a == b); // false
console.log(a === b); // false
console.log(a != b); // true
console.log(a !== b); // true
// 逻辑运算符
console.log(true && false); // false
console.log(true || false); // true
console.log(!true); // false
(三)条件语句¶
// if-else 语句
let score = 85;
if (score >= 90) {
console.log("优秀");
} else if (score >= 80) {
console.log("良好");
} else if (score >= 60) {
console.log("及格");
} else {
console.log("不及格");
}
// switch 语句
let day = 3;
let dayName;
switch (day) {
case 1:
dayName = "星期一";
break;
case 2:
dayName = "星期二";
break;
case 3:
dayName = "星期三";
break;
default:
dayName = "未知";
}
(四)循环语句¶
// for 循环
for (let i = 0; i < 5; i++) {
console.log(i);
}
// while 循环
let i = 0;
while (i < 5) {
console.log(i);
i++;
}
// for...in 循环(遍历对象)
let person = {name: "张三", age: 20};
for (let key in person) {
console.log(key + ": " + person[key]);
}
// for...of 循环(遍历数组)
let fruits = ["苹果", "香蕉", "橙子"];
for (let fruit of fruits) {
console.log(fruit);
}
第三章:函数¶
(一)函数定义¶
// 函数声明
function add(a, b) {
return a + b;
}
// 函数表达式
const subtract = function(a, b) {
return a - b;
};
// 箭头函数
const multiply = (a, b) => a * b;
// 调用函数
console.log(add(3, 5)); // 8
console.log(subtract(10, 3)); // 7
console.log(multiply(4, 6)); // 24
(二)默认参数和剩余参数¶
// 默认参数
function greet(name = "朋友") {
return `你好,${name}!`;
}
// 剩余参数
function sumAll(...numbers) {
return numbers.reduce((sum, num) => sum + num, 0);
}
console.log(greet()); // 你好,朋友!
console.log(greet("张三")); // 你好,张三!
console.log(sumAll(1, 2, 3, 4)); // 10
第四章:数组和对象¶
(一)数组操作¶
// 创建数组
let fruits = ["苹果", "香蕉", "橙子"];
// 添加元素
fruits.push("葡萄"); // 添加到末尾
fruits.unshift("草莓"); // 添加到开头
// 删除元素
fruits.pop(); // 删除末尾元素
fruits.shift(); // 删除开头元素
// 数组方法
fruits.forEach((fruit, index) => {
console.log(`${index}: ${fruit}`);
});
let numbers = [3, 1, 4, 1, 5];
let doubled = numbers.map(num => num * 2); // [6, 2, 8, 2, 10]
let evens = numbers.filter(num => num % 2 === 0); // [4]
let sum = numbers.reduce((acc, num) => acc + num, 0); // 14
(二)对象操作¶
// 创建对象
let person = {
name: "张三",
age: 20,
city: "北京",
greet: function() {
return `你好,我是${this.name}`;
}
};
// 访问属性
console.log(person.name); // 张三
console.log(person["age"]); // 20
// 修改属性
person.age = 21;
person.city = "上海";
// 添加属性
person.email = "zhangsan@example.com";
// 删除属性
delete person.city;
// 对象方法
console.log(person.greet()); // 你好,我是张三
// 对象解构
const {name, age} = person;
console.log(name, age); // 张三 21
第五章:DOM 操作¶
(一)选择元素¶
// 通过 ID 选择
let element1 = document.getElementById("myId");
// 通过类名选择
let elements1 = document.getElementsByClassName("myClass");
// 通过标签名选择
let elements2 = document.getElementsByTagName("div");
// 通过选择器选择
let element2 = document.querySelector(".myClass");
let elements3 = document.querySelectorAll("div.myClass");
(二)修改元素¶
// 修改内容
element.textContent = "新的文本内容";
element.innerHTML = "<strong>新的 HTML 内容</strong>";
// 修改样式
element.style.color = "red";
element.style.fontSize = "18px";
// 修改属性
element.setAttribute("class", "newClass");
element.id = "newId";
// 添加和删除类
element.classList.add("highlight");
element.classList.remove("oldClass");
element.classList.toggle("active");
(三)事件处理¶
// 添加事件监听
element.addEventListener("click", function() {
console.log("元素被点击了");
});
// 移除事件监听
function handleClick() {
console.log("处理点击事件");
}
element.addEventListener("click", handleClick);
element.removeEventListener("click", handleClick);
// 常用事件
element.addEventListener("mouseover", function() {
// 鼠标悬停
});
element.addEventListener("mouseout", function() {
// 鼠标离开
});
element.addEventListener("keydown", function(event) {
// 键盘按下
console.log(event.key);
});
第六章:ES6+ 新特性¶
(一)解构赋值¶
// 数组解构
let [a, b, c] = [1, 2, 3];
console.log(a, b, c); // 1 2 3
// 跳过元素
let [x, , z] = [1, 2, 3];
console.log(x, z); // 1 3
// 默认值
let [m = 10, n = 20] = [5];
console.log(m, n); // 5 20
// 剩余元素
let [first, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(rest); // [2, 3, 4, 5]
// 对象解构
let {name, age, city = "未知"} = {name: "张三", age: 20};
console.log(name, age, city); // 张三 20 未知
// 重命名
let {name: userName, age: userAge} = {name: "李四", age: 25};
console.log(userName, userAge); // 李四 25
// 嵌套解构
let {address: {province, city: addr}} = {
address: {province: "北京", city: "朝阳区"}
};
console.log(province, addr); // 北京 朝阳区
(二)模板字符串¶
// 基本用法
let name = "张三";
let greeting = `你好,${name}!`;
console.log(greeting); // 你好,张三!
// 多行字符串
let html = `
<div class="card">
<h2>${name}</h2>
<p>这是内容</p>
</div>
`;
// 表达式
let price = 99;
let result = `总价:${price > 50 ? '打折' : '原价'} ${price}元`;
console.log(result); // 总价:打折 99元
// 标签模板
function highlight(strings, ...values) {
return strings.reduce((result, str, i) => {
return result + str + (values[i] ? `<mark>${values[i]}</mark>` : '');
}, '');
}
let name2 = "JavaScript";
let output = highlight`学习${name2}很有意思`;
console.log(output); // 学习<mark>JavaScript</mark>很有意思
(三)展开运算符和剩余参数¶
// 数组展开
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let merged = [...arr1, ...arr2];
console.log(merged); // [1, 2, 3, 4, 5, 6]
// 对象展开
let obj1 = {a: 1, b: 2};
let obj2 = {b: 3, c: 4};
let mergedObj = {...obj1, ...obj2};
console.log(mergedObj); // {a: 1, b: 3, c: 4}
// 浅拷贝
let copy = {...obj1};
// 剩余参数
function sum(...nums) {
return nums.reduce((total, n) => total + n, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15
// 解构中的剩余
let [head, ...tail] = [1, 2, 3, 4];
console.log(head); // 1
console.log(tail); // [2, 3, 4]
(四)Promise 和异步编程¶
// Promise 基础
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = {name: "张三", age: 20};
resolve(data);
// reject(new Error("请求失败"));
}, 1000);
});
}
// 使用 Promise
fetchData()
.then(data => console.log(data))
.catch(error => console.error(error))
.finally(() => console.log("完成"));
// Promise 链
function getUser() {
return Promise.resolve({id: 1, name: "张三"});
}
function getPosts(userId) {
return Promise.resolve([
{id: 1, title: "文章1"},
{id: 2, title: "文章2"}
]);
}
getUser()
.then(user => getPosts(user.id))
.then(posts => console.log(posts));
// Promise.all - 并行执行
let promise1 = Promise.resolve(1);
let promise2 = Promise.resolve(2);
let promise3 = Promise.resolve(3);
Promise.all([promise1, promise2, promise3])
.then(results => console.log(results)); // [1, 2, 3]
// Promise.race - 竞争执行
Promise.race([promise1, promise2, promise3])
.then(result => console.log(result)); // 1
// Promise.allSettled - 等待所有完成
Promise.allSettled([promise1, promise2, promise3])
.then(results => console.log(results));
(五)async/await¶
// async 函数
async function getUserData() {
try {
let response = await fetch('https://api.example.com/user');
let data = await response.json();
return data;
} catch (error) {
console.error('请求失败:', error);
}
}
// 并行执行多个 async
async function loadAllData() {
const [users, posts] = await Promise.all([
fetch('/api/users').then(r => r.json()),
fetch('/api/posts').then(r => r.json())
]);
return {users, posts};
}
// 循环中的 async
async function processItems(items) {
for (let item of items) {
await processItem(item);
}
}
// 常见错误
// 错误1:在循环中使用 await(会串行执行)
async function wrong() {
for (let i = 0; i < 5; i++) {
await delay(1000); // 会等待5秒
}
}
// 正确:使用 Promise.all
async function correct() {
await Promise.all(
Array(5).fill().map(() => delay(1000))
); // 只等1秒
}
(六)Map 和 Set¶
// Map
let map = new Map();
map.set('name', '张三');
map.set('age', 20);
map.set(1, '数字键');
console.log(map.get('name')); // 张三
console.log(map.size); // 3
console.log(map.has('age')); // true
// Map 迭代
for (let [key, value] of map) {
console.log(`${key}: ${value}`);
}
// Map 与对象转换
let obj = {a: 1, b: 2};
let mapFromObj = new Map(Object.entries(obj));
let objFromMap = Object.fromEntries(map);
// Set
let set = new Set([1, 2, 3, 3, 4, 4, 5]);
console.log(set); // Set {1, 2, 3, 4, 5}
console.log(set.size); // 5
// Set 方法
set.add(6);
set.delete(1);
set.has(3); // true
// Set 去重
let arr = [1, 2, 2, 3, 3, 4];
let unique = [...new Set(arr)]; // [1, 2, 3, 4]
// Set 迭代
for (let item of set) {
console.log(item);
}
// Set 操作
let setA = new Set([1, 2, 3]);
let setB = new Set([3, 4, 5]);
// 并集
let union = new Set([...setA, ...setB]);
// 交集
let intersection = new Set([...setA].filter(x => setB.has(x)));
// 差集
let difference = new Set([...setA].filter(x => !setB.has(x)));
(七)类¶
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return `你好,我是${this.name},今年${this.age}岁`;
}
// 静态方法
static create(name, age) {
return new Person(name, age);
}
// getter
get info() {
return `${this.name} (${this.age})`;
}
// setter
set name(value) {
this._name = value.toUpperCase();
}
}
// 继承
class Student extends Person {
constructor(name, age, grade) {
super(name, age);
this.grade = grade;
}
study() {
return `${this.name}正在学习`;
}
greet() {
return `${super.greet()},我是${this.grade}学生`;
}
}
let student = new Student("张三", 20, "大二");
console.log(student.greet()); // 你好,我是张三,今年20岁,我是大二学生
console.log(student.study()); // 张三正在学习
(八)模块化¶
// math.js - 导出
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export default class Calculator {
add(a, b) { return a + b; }
subtract(a, b) { return a - b; }
}
// app.js - 导入
import Calculator, {PI, add} from './math.js';
const calc = new Calculator();
console.log(calc.add(1, 2)); // 3
console.log(PI); // 3.14159
console.log(add(3, 4)); // 7
// 动态导入
async function loadModule() {
const module = await import('./math.js');
console.log(module.add(1, 2));
}
(九)可选链和空值合并¶
// 可选链 ?. 访问嵌套属性
let user = {
name: "张三",
address: {
city: "北京"
}
};
console.log(user?.address?.city); // 北京
console.log(user?.phone?.number); // undefined
console.log(user?.address?.zipCode); // undefined
// 可选链调用方法
user.greet?.(); // 如果greet存在就调用
// 空值合并 ??
let value1 = null ?? "默认值"; // "默认值"
let value2 = undefined ?? "默认值"; // "默认值"
let value3 = 0 ?? "默认值"; // 0
let value4 = "" ?? "默认值"; // ""
// 与 || 的区别
let v1 = 0 || "默认值"; // "默认值"
let v2 = 0 ?? "默认值"; // 0
// 组合使用
let config = {
host: "localhost",
port: null
};
let host = config.host ?? "127.0.0.1"; // "localhost"
let port = config.port ?? 3000; // 3000
(十)Array 方法扩展¶
let numbers = [1, 2, 3, 4, 5];
// Array.from
let arr = Array.from({length: 5}, (_, i) => i + 1); // [1, 2, 3, 4, 5]
// Array.of
let arr2 = Array.of(1, 2, 3); // [1, 2, 3]
// find 和 findIndex
let found = numbers.find(n => n > 3); // 4
let index = numbers.findIndex(n => n > 3); // 3
// includes
numbers.includes(3); // true
// flat 和 flatMap
let nested = [1, [2, 3], [4, [5, 6]]];
nested.flat(); // [1, 2, 3, 4, [5, 6]]
nested.flat(2); // [1, 2, 3, 4, 5, 6]
nested.flat(Infinity); // [1, 2, 3, 4, 5, 6]
let sentences = ["hello world", "foo bar"];
sentences.flatMap(s => s.split(' ')); // ["hello", "world", "foo", "bar"]
// at 方法
let arr3 = ['a', 'b', 'c', 'd'];
arr3.at(0); // 'a'
arr3.at(-1); // 'd' (支持负索引)
// entries, keys, values
for (let [index, value] of numbers.entries()) {
console.log(`${index}: ${value}`);
}
第七章:练习题目¶
基础练习¶
- 变量和数据类型
- 创建不同类型的变量
-
进行类型转换
-
条件语句
- 判断数字的正负
-
判断成绩等级
-
循环语句
- 计算 1 到 100 的和
- 打印九九乘法表
进阶练习¶
- 函数
- 定义函数计算阶乘
-
定义函数判断质数
-
数组操作
- 找出数组中的最大值
-
筛选数组中的偶数
-
对象操作
- 创建对象表示学生信息
- 遍历对象属性
综合练习¶
- DOM 操作
- 创建动态导航栏
-
创建待办事项应用
-
事件处理
- 创建简单的计算器
-
创建猜数字游戏
-
综合应用
- 创建完整的个人网站
- 创建产品展示网站
恭喜你完成了 JavaScript 教程的学习!现在你已经掌握了 HTML、CSS 和 JavaScript,可以开始创建动态网页了!