JavaScript 简介

JavaScript(JS)是一种具有函数优先特性的轻量级、解释型或者说即时编译型的编程语言。在 Web 网页中,JavaScript 代码可以修改 HTML 内容、样式和结构,响应用户操作,以及与服务器进行交互。除此之外,JavaScript 还被应用到了很多非浏览器环境中,例如 Node.js。进一步说,JavaScript 是一种基于原型、多范式、单线程的动态语言,并且支持面向对象、命令式和声明式(如函数式编程)风格。

JavaScript 基础

变量和数据类型

JavaScript 中有三种声明变量的方式:varletconst

变量声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// var - 函数作用域,可重复声明,可修改
var name = "JavaScript";
var name = "JS"; // 可以重复声明

// let - 块级作用域,不可重复声明,可修改
let age = 25;
age = 26; // 可以修改值
// let age = 30; // 错误:不能重复声明

// const - 块级作用域,不可重复声明,不可修改(但对象的属性可以修改)
const PI = 3.14159;
// PI = 3; // 错误:不能修改常量值

// const对象的属性可以修改
const person = { name: "Alice", age: 30 };
person.age = 31; // 可以修改对象的属性
// person = {}; // 错误:不能重新赋值整个对象

数据类型

JavaScript 有8种数据类型:

  1. 基本数据类型(原始类型):

    • String(字符串)
    • Number(数字)
    • Boolean(布尔)
    • Undefined(未定义)
    • Null(空)
    • Symbol(符号,ES6新增)
    • BigInt(大整数,ES2020新增)
  2. 引用数据类型:

    • Object(对象):包括普通对象、数组、函数等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// String - 字符串
let str1 = "Hello";
let str2 = 'World';
let str3 = `Template: ${str1} ${str2}`; // 模板字符串

// Number - 数字
let num1 = 100; // 整数
let num2 = 3.14; // 浮点数
let num3 = 0xff; // 十六进制
let num4 = 3e8; // 科学计数法
let num5 = NaN; // 非数字
let num6 = Infinity; // 无穷大

// Boolean - 布尔值
let isActive = true;
let isLoading = false;

// Undefined - 未定义
let unknown;
console.log(unknown); // undefined

// Null - 空值
let empty = null;

// Symbol - 唯一标识符
let sym1 = Symbol('id');
let sym2 = Symbol('id');
console.log(sym1 === sym2); // false,即使描述相同也是唯一的

// BigInt - 大整数
let bigNumber = 9007199254740991n; // 用n结尾表示BigInt

// Object - 对象
let person = {
name: "张三",
age: 30,
isStudent: false,
greet: function() {
return `你好,我是${this.name}`;
}
};

// Array - 数组(也是Object的一种)
let colors = ["红", "绿", "蓝"];
let mixed = [1, "text", true, null, {key: "value"}, [1, 2]];

// Function - 函数(也是Object的一种)
function add(a, b) {
return a + b;
}

// 箭头函数
const multiply = (a, b) => a * b;

类型检查与转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 使用typeof检查类型
console.log(typeof "Hello"); // "string"
console.log(typeof 123); // "number"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (这是JS的一个历史遗留bug)
console.log(typeof {}); // "object"
console.log(typeof []); // "object" (数组也是对象)
console.log(typeof function(){}); // "function"

// 类型转换
// 显式转换
let num = Number("123"); // 字符串转数字: 123
let str = String(456); // 数字转字符串: "456"
let bool = Boolean(1); // 转布尔值: true (0, "", null, undefined, NaN转为false,其他为true)

// 隐式转换
let result1 = "3" + 2; // "32" (数字被转为字符串)
let result2 = "3" - 2; // 1 (字符串被转为数字)
let result3 = "3" * "2"; // 6 (字符串被转为数字)

变量作用域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 全局作用域
let globalVar = "我是全局变量";

function testScope() {
// 函数作用域
let functionVar = "我是函数变量";

if(true) {
// 块级作用域
let blockVar = "我是块级变量(let)";
var varInBlock = "我是用var声明的变量";
console.log(globalVar); // 可访问
console.log(functionVar); // 可访问
console.log(blockVar); // 可访问
}

console.log(globalVar); // 可访问
console.log(functionVar); // 可访问
// console.log(blockVar); // 错误!不可访问
console.log(varInBlock); // 可访问,因为var没有块级作用域
}

testScope();
console.log(globalVar); // 可访问
// console.log(functionVar); // 错误!不可访问
// console.log(varInBlock); // 错误!不可访问

解构赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 数组解构
let [a, b, c] = [1, 2, 3];
console.log(a, b, c); // 1 2 3

// 对象解构
let {name, age} = {name: "李四", age: 25};
console.log(name, age); // "李四" 25

// 设置默认值
let [x = 0, y = 0] = [5];
console.log(x, y); // 5 0

// 交换变量
let m = 10, n = 20;
[m, n] = [n, m];
console.log(m, n); // 20 10

// 忽略某些值
let [first, , third] = [1, 2, 3];
console.log(first, third); // 1 3

// 剩余参数
let [head, ...tail] = [1, 2, 3, 4];
console.log(head, tail); // 1 [2, 3, 4]

运算符

JavaScript 提供了多种操作符用于执行不同类型的操作。

算术运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 基本算术运算符
let sum = 10 + 5; // 加法: 15
let diff = 10 - 5; // 减法: 5
let product = 10 * 5; // 乘法: 50
let quotient = 10 / 5; // 除法: 2
let remainder = 10 % 3;// 取余: 1
let exp = 2 ** 3; // 幂运算: 8

// 自增和自减
let count = 5;
count++; // 后置自增: count = 6
++count; // 前置自增: count = 7
count--; // 后置自减: count = 6
--count; // 前置自减: count = 5

// 前置和后置的区别
let a = 5;
let b = a++; // b = 5, a = 6,后置先赋值再自增
let c = 5;
let d = ++c; // d = 6, c = 6,前置先自增再赋值

赋值运算符

1
2
3
4
5
6
7
8
9
10
// 基本赋值
let x = 10;

// 复合赋值
x += 5; // 等同于 x = x + 5; 结果:15
x -= 3; // 等同于 x = x - 3; 结果:12
x *= 2; // 等同于 x = x * 2; 结果:24
x /= 4; // 等同于 x = x / 4; 结果:6
x %= 4; // 等同于 x = x % 4; 结果:2
x **= 2; // 等同于 x = x ** 2; 结果:4

比较运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 相等比较
console.log(5 == 5); // true
console.log(5 == "5"); // true (类型自动转换)
console.log(5 === "5"); // false (严格相等,不进行类型转换)

// 不等比较
console.log(5 != 8); // true
console.log(5 != "5"); // false (类型自动转换)
console.log(5 !== "5"); // true (严格不等,不进行类型转换)

// 大小比较
console.log(5 > 3); // true
console.log(5 >= 5); // true
console.log(5 < 10); // true
console.log(5 <= 4); // false

// 特殊比较
console.log(null == undefined); // true
console.log(null === undefined); // false
console.log(NaN == NaN); // false (NaN不等于任何值,包括自身)
console.log(NaN === NaN); // false

逻辑运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 逻辑与 (AND)
console.log(true && true); // true
console.log(true && false); // false
console.log(false && true); // false
console.log(false && false); // false

// 逻辑或 (OR)
console.log(true || true); // true
console.log(true || false); // true
console.log(false || true); // true
console.log(false || false); // false

// 逻辑非 (NOT)
console.log(!true); // false
console.log(!false); // true

// 短路运算
console.log(false && someFunction()); // false,someFunction不会执行
console.log(true || someFunction()); // true,someFunction不会执行

// 逻辑运算符的返回值
console.log("Hello" && "World"); // "World" (返回最后一个真值)
console.log("" && "World"); // "" (返回第一个假值)
console.log("Hello" || "World"); // "Hello" (返回第一个真值)
console.log("" || "World"); // "World" (若第一个为假,返回第二个值)

条件(三元)运算符

1
2
3
4
5
6
7
8
9
// 条件表达式 ? 值1 : 值2
let age = 20;
let status = age >= 18 ? "成年" : "未成年";
console.log(status); // "成年"

// 嵌套三元运算符
let score = 85;
let grade = score >= 90 ? "A" : (score >= 80 ? "B" : (score >= 70 ? "C" : "D"));
console.log(grade); // "B"

其他运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// typeof运算符
console.log(typeof 42); // "number"
console.log(typeof "hello"); // "string"

// instanceof运算符
let arr = [];
console.log(arr instanceof Array); // true

// in运算符 (检查属性是否存在)
let car = {make: "Toyota", model: "Corolla"};
console.log("make" in car); // true
console.log("color" in car); // false

// 空值合并运算符 (??) - ES2020
let user = null;
let displayName = user ?? "Guest"; // "Guest"

// 可选链运算符 (?.) - ES2020
let obj = {outer: {inner: {value: 42}}};
console.log(obj?.outer?.inner?.value); // 42
console.log(obj?.outer?.missing?.value); // undefined (不报错)

控制流

条件语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// if语句
let temperature = 25;

if (temperature > 30) {
console.log("天气炎热");
} else if (temperature > 20) {
console.log("天气适宜");
} else {
console.log("天气凉爽");
}

// switch语句
let day = "星期三";

switch (day) {
case "星期一":
console.log("开始工作");
break;
case "星期三":
console.log("周中了");
break;
case "星期五":
console.log("周末来临");
break;
default:
console.log("普通的一天");
break;
}

循环语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// for循环
for (let i = 0; i < 5; i++) {
console.log(`计数: ${i}`);
}

// while循环
let count = 0;
while (count < 5) {
console.log(`while计数: ${count}`);
count++;
}

// do...while循环
let num = 0;
do {
console.log(`do-while计数: ${num}`);
num++;
} while (num < 5);

// for...in循环 (用于对象)
let person = {name: "李华", age: 25, job: "工程师"};
for (let key in person) {
console.log(`${key}: ${person[key]}`);
}

// for...of循环 (用于可迭代对象)
let colors = ["红", "绿", "蓝"];
for (let color of colors) {
console.log(color);
}

// 跳出循环
for (let i = 0; i < 10; i++) {
if (i === 3) continue; // 跳过当前迭代
if (i === 7) break; // 结束整个循环
console.log(i);
}

函数

函数声明与表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 函数声明
function greet(name) {
return `你好,${name}!`;
}
console.log(greet("小明")); // "你好,小明!"

// 函数表达式
const sayHello = function(name) {
return `你好,${name}!`;
};
console.log(sayHello("小红")); // "你好,小红!"

// 箭头函数
const welcome = (name) => `欢迎,${name}!`;
console.log(welcome("小张")); // "欢迎,小张!"

// 函数参数
function add(a, b = 0) { // 设置默认参数
return a + b;
}
console.log(add(5, 3)); // 8
console.log(add(5)); // 5 (b默认为0)

// 剩余参数
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4)); // 10

作用域和闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 闭包示例
function createCounter() {
let count = 0;

// 内部函数形成闭包,可以访问外部函数的变量
return function() {
count += 1;
return count;
};
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
// count变量在外部无法访问,但内部函数可以"记住"它

this关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 在对象方法中
const user = {
name: "张三",
sayHi() {
console.log(`你好,我是${this.name}`);
}
};
user.sayHi(); // "你好,我是张三"

// 在全局函数中
function showThis() {
console.log(this); // 在浏览器中是window对象
}
showThis();

// 在事件处理函数中
/*
button.addEventListener('click', function() {
console.log(this); // 指向触发事件的元素(button)
});
*/

// 箭头函数中
const obj = {
name: "李四",
regularFunction: function() {
console.log(this.name); // "李四"

// 箭头函数不绑定自己的this,而是继承外围作用域的this
const arrowFunction = () => {
console.log(this.name); // 仍然是"李四"
};
arrowFunction();
}
};
obj.regularFunction();

对象和数组

对象基础

对象是JavaScript中的复合数据类型,用于存储多个相关数据和功能的集合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 对象字面量创建
const person = {
firstName: "张",
lastName: "三",
age: 25,
isStudent: false,

// 对象方法
fullName() {
return this.firstName + this.lastName;
}
};

// 访问对象属性
console.log(person.firstName); // 点表示法:张
console.log(person["lastName"]); // 方括号表示法:三
console.log(person.fullName()); // 调用方法:张三

// 添加新属性
person.email = "zhangsan@example.com";

// 修改属性
person.age = 26;

// 删除属性
delete person.isStudent;

// 检查属性是否存在
console.log("email" in person); // true
console.log(person.hasOwnProperty("age")); // true

// 遍历对象
for (let key in person) {
console.log(`${key}: ${person[key]}`);
}

// 获取所有键和值
const keys = Object.keys(person); // ["firstName", "lastName", "age", "email", ...]
const values = Object.values(person); // ["张", "三", 26, "zhangsan@example.com", ...]
const entries = Object.entries(person); // [["firstName", "张"], ["lastName", "三"], ...]

对象方法和构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 构造函数
function Person(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;

this.fullName = function() {
return this.firstName + this.lastName;
};
}

// 使用构造函数创建实例
const person1 = new Person("李", "四", 30);
const person2 = new Person("王", "五", 25);

console.log(person1.fullName()); // 李四
console.log(person2.age); // 25

// Object.create()方法
const personProto = {
greeting() {
return `你好,我是${this.name}`;
}
};

const student = Object.create(personProto);
student.name = "小明";
console.log(student.greeting()); // 你好,我是小明

数组详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// 创建数组
let fruits = ["苹果", "香蕉", "橙子"];
let numbers = new Array(1, 2, 3, 4, 5);
let mixed = [1, "文本", true, {name: "对象"}, [1, 2]];

// 访问数组元素
console.log(fruits[0]); // 苹果
console.log(fruits[fruits.length - 1]); // 橙子

// 修改数组元素
fruits[1] = "梨";
console.log(fruits); // ["苹果", "梨", "橙子"]

// 基本数组方法
fruits.push("葡萄"); // 添加到末尾: ["苹果", "梨", "橙子", "葡萄"]
let lastFruit = fruits.pop(); // 移除末尾: lastFruit = "葡萄", fruits = ["苹果", "梨", "橙子"]
let firstFruit = fruits.shift(); // 移除开头: firstFruit = "苹果", fruits = ["梨", "橙子"]
fruits.unshift("草莓"); // 添加到开头: ["草莓", "梨", "橙子"]

// 查找元素
let index = fruits.indexOf("梨"); // 1
let includesOrange = fruits.includes("橙子"); // true

// 数组变换
let nums = [1, 2, 3, 4, 5];

// map - 返回新数组,每个元素都经过处理
let doubled = nums.map(num => num * 2); // [2, 4, 6, 8, 10]

// filter - 返回满足条件的元素组成的新数组
let evens = nums.filter(num => num % 2 === 0); // [2, 4]

// reduce - 将数组压缩为单个值
let sum = nums.reduce((total, num) => total + num, 0); // 15

// forEach - 遍历数组元素
nums.forEach(num => console.log(num)); // 依次打印: 1, 2, 3, 4, 5

// 数组排序
let letters = ["c", "a", "d", "b"];
letters.sort(); // ["a", "b", "c", "d"]
nums.sort((a, b) => b - a); // 降序: [5, 4, 3, 2, 1]

// 数组切片
let sliced = nums.slice(1, 3); // [4, 3] (索引1到索引3之前的元素)
let removed = nums.splice(1, 2); // 从索引1开始移除2个元素,返回移除的元素

// 数组连接
let combined = [1, 2].concat([3, 4], [5]); // [1, 2, 3, 4, 5]
// 或者使用扩展运算符
let combined2 = [...[1, 2], ...[3, 4], ...[5]]; // [1, 2, 3, 4, 5]

// 展开多维数组
let flattened = [1, [2, [3, 4]]].flat(2); // [1, 2, 3, 4]

ES6+ 新特性

ES6(ECMAScript 2015)及后续版本引入了许多重要的JavaScript语言特性。

箭头函数详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 基本箭头函数
const add = (a, b) => a + b;

// 单个参数时可省略括号
const square = x => x * x;

// 多行函数体使用花括号
const greet = name => {
const message = `你好,${name}!`;
return message;
};

// 箭头函数与this
const person = {
name: "张三",
// 普通函数
sayHiLater: function() {
setTimeout(function() {
console.log(`你好,我是${this.name}`); // this指向window,输出"你好,我是undefined"
}, 1000);
},
// 箭头函数
sayHiLaterArrow: function() {
setTimeout(() => {
console.log(`你好,我是${this.name}`); // this指向person,输出"你好,我是张三"
}, 1000);
}
};

模板字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 基本用法
const name = "JavaScript";
const greeting = `Hello, ${name}!`;

// 多行字符串
const multiLine = `
这是第一行
这是第二行
这是第三行
`;

// 表达式插值
const a = 10, b = 5;
const result = `${a} + ${b} = ${a + b}`;

// 标签模板
function highlight(strings, ...values) {
return strings.reduce((result, str, i) => {
const value = values[i] || '';
return `${result}${str}<span class="highlight">${value}</span>`;
}, '');
}

const user = "张三";
const role = "管理员";
const html = highlight`用户 ${user}${role}`;
// 结果: "用户 <span class="highlight">张三</span> 是 <span class="highlight">管理员</span>"

解构赋值详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 数组解构的高级用法
const [first, ...rest] = [1, 2, 3, 4]; // first = 1, rest = [2, 3, 4]
const [a, , c] = [1, 2, 3]; // a = 1, c = 3, 跳过中间元素
const [x = 0, y = 0] = []; // x = 0, y = 0, 提供默认值

// 对象解构的高级用法
const { name, age = 20 } = { name: "李四" }; // name = "李四", age = 20 (默认值)
const { name: fullName } = { name: "王五" }; // fullName = "王五" (属性重命名)
const { a: { b } } = { a: { b: 'nested' } }; // b = "nested" (嵌套解构)

// 函数参数解构
function printPersonInfo({ name, age = 18, city = "北京" }) {
console.log(`${name}, ${age}岁, 来自${city}`);
}
printPersonInfo({ name: "赵六", age: 25 }); // "赵六, 25岁, 来自北京"

扩展运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 数组展开
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]

// 函数参数展开
function sum(a, b, c) {
return a + b + c;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers)); // 6

// 对象展开
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3, b: 3 }; // { a: 1, b: 3, c: 3 } (b被覆盖)

// 数组复制
const originalArray = [1, 2, 3];
const copyArray = [...originalArray]; // 创建新数组,而不是引用

// 对象复制
const originalObject = { a: 1, b: { c: 2 } };
const copyObject = { ...originalObject }; // 浅拷贝
// 注意:这只是浅拷贝,嵌套对象仍然是引用

类(Class)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 基本类语法
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}

// 实例方法
sayHello() {
return `你好,我是${this.name}${this.age}岁`;
}

// 静态方法
static createAnonymous() {
return new Person("无名氏", 0);
}
}

const person = new Person("张三", 30);
console.log(person.sayHello()); // "你好,我是张三,30岁"
const anonymous = Person.createAnonymous();

// 类继承
class Student extends Person {
constructor(name, age, grade) {
// 调用父类构造函数
super(name, age);
this.grade = grade;
}

// 覆盖父类方法
sayHello() {
return `${super.sayHello()},我在${this.grade}年级`;
}

// 新增方法
study() {
return `${this.name}正在学习`;
}
}

const student = new Student("小明", 15, "初三");
console.log(student.sayHello()); // "你好,我是小明,15岁,我在初三年级"

模块系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 导出 (math.js)
export const PI = 3.14159;

export function add(a, b) {
return a + b;
}

export function multiply(a, b) {
return a * b;
}

export default class Calculator {
add(a, b) {
return a + b;
}
}

// 导入 (app.js)
import Calculator, { PI, add, multiply as mult } from './math.js';

console.log(PI); // 3.14159
console.log(add(2, 3)); // 5
console.log(mult(2, 3)); // 6 (重命名为mult)

const calc = new Calculator();
console.log(calc.add(5, 3)); // 8

// 导入所有
import * as MathUtils from './math.js';
console.log(MathUtils.PI); // 3.14159
console.log(MathUtils.add(2, 3)); // 5

异步编程

回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 传统回调函数处理异步
function fetchData(callback) {
setTimeout(() => {
const data = { name: "示例数据", timestamp: Date.now() };
callback(null, data); // 第一个参数通常是错误,第二个是数据
}, 1000);
}

fetchData((error, data) => {
if (error) {
console.error("发生错误:", error);
return;
}
console.log("数据:", data);

// 回调地狱示例
fetchData((error, moreData) => {
if (error) {
console.error("发生错误:", error);
return;
}
console.log("更多数据:", moreData);

fetchData((error, evenMoreData) => {
// 嵌套更深...
});
});
});

Promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 创建Promise
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = Math.random() > 0.3; // 70%成功率
if (success) {
resolve({ name: "示例数据", timestamp: Date.now() });
} else {
reject(new Error("无法获取数据"));
}
}, 1000);
});
}

// 使用Promise
fetchData()
.then(data => {
console.log("数据:", data);
return fetchData(); // 链式调用
})
.then(moreData => {
console.log("更多数据:", moreData);
return fetchData();
})
.then(evenMoreData => {
console.log("更多更多数据:", evenMoreData);
})
.catch(error => {
// 捕获链中任何一个环节的错误
console.error("发生错误:", error);
})
.finally(() => {
// 无论成功失败都会执行
console.log("请求完成");
});

// Promise组合
Promise.all([fetchData(), fetchData(), fetchData()])
.then(resultsArray => {
console.log("所有请求完成:", resultsArray);
})
.catch(error => {
console.error("至少一个请求失败:", error);
});

Promise.race([fetchData(), fetchData(), fetchData()])
.then(firstResult => {
console.log("最快的请求结果:", firstResult);
})
.catch(error => {
console.error("最快的请求失败:", error);
});

Async/Await

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 使用async/await简化Promise处理
async function fetchAllData() {
try {
// 等待Promise完成
const data = await fetchData();
console.log("第一组数据:", data);

// 顺序执行,但代码像同步一样清晰
const moreData = await fetchData();
console.log("第二组数据:", moreData);

// 并行执行
const [result1, result2] = await Promise.all([
fetchData(),
fetchData()
]);
console.log("并行结果:", result1, result2);

return "所有数据获取成功";
} catch (error) {
// 捕获任何一步出现的错误
console.error("处理数据时出错:", error);
throw error; // 可以重新抛出
}
}

// 调用async函数
fetchAllData()
.then(message => console.log(message))
.catch(error => console.error("最外层捕获:", error));

// 立即执行的异步函数
(async () => {
try {
const result = await fetchAllData();
console.log(result);
} catch (error) {
console.error(error);
}
})();

DOM操作与浏览器API

DOM选择与操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 选择元素
const heading = document.getElementById('main-heading');
const paragraphs = document.getElementsByTagName('p');
const specialElements = document.getElementsByClassName('special');
const firstButton = document.querySelector('button');
const allLinks = document.querySelectorAll('a.external');

// 修改内容
heading.textContent = '新标题';
heading.innerHTML = '新标题 <span>带HTML</span>';

// 修改属性
const img = document.querySelector('img');
img.src = 'new-image.jpg';
img.alt = '图片描述';

// 自定义属性
img.setAttribute('data-category', 'nature');
const category = img.getAttribute('data-category');
// 或使用dataset API
img.dataset.category = 'nature';
const category2 = img.dataset.category;

// 修改样式
const element = document.querySelector('.highlight');
element.style.color = 'red';
element.style.fontSize = '20px';
element.style.display = 'none';
// 添加/移除/切换类
element.classList.add('active');
element.classList.remove('hidden');
element.classList.toggle('visible');
element.classList.contains('active'); // true

// 创建新元素
const newParagraph = document.createElement('p');
newParagraph.textContent = '这是新段落';
// 添加到DOM
document.body.appendChild(newParagraph);
// 插入到特定位置
const container = document.querySelector('.container');
container.insertBefore(newParagraph, container.firstChild);

// 移除元素
container.removeChild(newParagraph);
// 或者自我删除
newParagraph.remove();

事件处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 添加事件监听器
const button = document.querySelector('button');
button.addEventListener('click', function(event) {
console.log('按钮被点击了!');
console.log('事件对象:', event);
// 阻止默认行为
event.preventDefault();
// 阻止事件冒泡
event.stopPropagation();
});

// 使用箭头函数和事件对象
const input = document.querySelector('input');
input.addEventListener('input', (e) => {
console.log('输入值:', e.target.value);
});

// 移除事件监听器
function handleClick() {
console.log('处理点击');
}
button.addEventListener('click', handleClick);
// 稍后移除
button.removeEventListener('click', handleClick);

// 事件委托(代理)
const list = document.querySelector('ul');
list.addEventListener('click', (event) => {
// 检查实际点击的是哪个子元素
if (event.target.tagName === 'LI') {
console.log('点击了列表项:', event.target.textContent);
}
});

// 常见事件类型
document.addEventListener('DOMContentLoaded', () => {
console.log('DOM完全加载');
});
window.addEventListener('load', () => {
console.log('页面完全加载,包括所有资源');
});
window.addEventListener('resize', () => {
console.log('窗口大小改变');
});
document.addEventListener('scroll', () => {
console.log('页面滚动');
});

Fetch API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// 基本GET请求
fetch('https://api.example.com/data')
.then(response => {
// 检查响应状态
if (!response.ok) {
throw new Error(`HTTP错误 ${response.status}`);
}
return response.json(); // 解析JSON响应
})
.then(data => {
console.log('数据:', data);
})
.catch(error => {
console.error('获取数据出错:', error);
});

// POST请求发送JSON数据
fetch('https://api.example.com/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
},
body: JSON.stringify({
name: '新项目',
description: '项目描述'
})
})
.then(response => response.json())
.then(data => console.log('创建结果:', data))
.catch(error => console.error('错误:', error));

// 使用async/await和Fetch
async function fetchUserData(userId) {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTP错误 ${response.status}`);
}
const userData = await response.json();
return userData;
} catch (error) {
console.error('获取用户数据失败:', error);
throw error;
}
}

// 文件上传
async function uploadFile(file) {
const formData = new FormData();
formData.append('file', file);

try {
const response = await fetch('https://api.example.com/upload', {
method: 'POST',
body: formData
});
return await response.json();
} catch (error) {
console.error('文件上传失败:', error);
throw error;
}
}

// 请求中止
const controller = new AbortController();
const { signal } = controller;

fetch('https://api.example.com/data', { signal })
.then(response => response.json())
.then(data => console.log('数据:', data))
.catch(error => {
if (error.name === 'AbortError') {
console.log('请求被取消');
} else {
console.error('错误:', error);
}
});

// 5秒后中止请求
setTimeout(() => controller.abort(), 5000);

错误处理与调试

try…catch使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// 基本try...catch
try {
// 可能会抛出错误的代码
const result = riskyOperation();
console.log('操作成功:', result);
} catch (error) {
// 处理错误
console.error('捕获到错误:', error.message);
// 可以根据错误类型进行不同处理
if (error instanceof TypeError) {
console.log('类型错误');
} else if (error instanceof ReferenceError) {
console.log('引用错误');
}
} finally {
// 无论try成功还是catch捕获到错误,都会执行
console.log('清理资源');
}

// 异步函数中的错误处理
async function processData() {
try {
const data = await fetchData();
const processed = await processResult(data);
return processed;
} catch (error) {
console.error('处理数据时出错:', error);
// 可以返回默认值或重新抛出错误
return { error: true, message: error.message };
}
}

// 自定义错误
class ValidationError extends Error {
constructor(message, field) {
super(message);
this.name = 'ValidationError';
this.field = field;
}
}

function validateUser(user) {
if (!user.name) {
throw new ValidationError('名称不能为空', 'name');
}
if (!user.email) {
throw new ValidationError('邮箱不能为空', 'email');
}
}

try {
validateUser({ name: 'Alice' });
} catch (error) {
if (error instanceof ValidationError) {
console.log(`字段 ${error.field} 验证失败: ${error.message}`);
} else {
console.error('未知错误:', error);
}
}

// 全局错误处理
window.addEventListener('error', (event) => {
console.error('全局错误:', event.error);
// 防止浏览器显示错误
event.preventDefault();
});

// 未捕获的Promise拒绝
window.addEventListener('unhandledrejection', (event) => {
console.warn('未处理的Promise拒绝:', event.reason);
event.preventDefault();
});

调试技巧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// 断点
function complexFunction(a, b) {
let result = a * 2;
// 可以在开发工具中在此行设置断点
result += b;
return result * b;
}

// debugger语句 (临时断点)
function findBug(data) {
let processed = [];
for (let i = 0; i < data.length; i++) {
if (data[i].value < 0) {
debugger; // 代码执行将在此暂停(开发工具打开时)
processed.push(data[i].value * -1);
} else {
processed.push(data[i].value);
}
}
return processed;
}

// 控制台API
console.log('普通信息');
console.info('信息'); // 通常和log渲染相同
console.warn('警告'); // 通常显示黄色警告图标
console.error('错误'); // 通常显示红色错误图标
console.table([ // 以表格形式显示数组或对象
{ name: '张三', age: 25 },
{ name: '李四', age: 30 }
]);
console.group('分组标题');
console.log('分组内的消息1');
console.log('分组内的消息2');
console.groupEnd();

// 计时功能
console.time('操作耗时');
// 耗时操作...
for (let i = 0; i < 1000000; i++) {
// 模拟耗时操作
}
console.timeEnd('操作耗时'); // 显示:"操作耗时: 10ms"

// 跟踪函数调用
function a() { b(); }
function b() { c(); }
function c() { console.trace('函数调用堆栈'); }
a(); // 显示从a到b到c的调用堆栈

// 条件断点
// 在开发者工具中,可以设置条件断点,只有在满足特定条件时才暂停
// 例如,在循环中仅当i等于特定值时暂停

推荐的 JavaScript 学习资源

课程推荐:

W3Schools:🛫
MDN Web Docs:🛫

项目实践:
FreeCodeCamp:🛫

❗❗❗ 学习重点 🤔:

  1. 基本语法和数据类型

    • 变量声明varletconst 的区别及作用
      • 变量提升现象与暂时性死区
      • 全局变量与window对象的关系
      • 何时使用const与let的最佳实践
      • 块级作用域与函数作用域的实际应用场景
    • 数据类型:字符串、数字、布尔值、undefined、null、对象(Object)、数组(Array)、Symbol 和 BigInt
      • 原始类型vs引用类型的内存模型
      • Symbol的实际应用场景与唯一性保证
      • BigInt处理大数字计算的使用方法
      • null与undefined的区别与应用场景
      • NaN的特性与isNaN/Number.isNaN的区别
    • 类型转换:隐式转换与显式转换(如 String(), Number() 等)
      • 强制类型转换的常见陷阱
      • 运算符导致的隐式转换规则
      • parseInt/parseFloat与Number转换的区别
      • valueOf与toString方法在转换中的作用
    • 操作符:算术操作符、比较操作符、逻辑操作符、赋值操作符、三元运算符、位运算符等
      • 位运算在实际开发中的高效应用
      • 逻辑运算符短路求值的应用技巧
      • ==与===的区别及何时使用
      • 复合赋值操作符及其优化
  2. 控制流

    • 条件语句ifelseswitch 语句
      • 条件表达式的真值与假值评估
      • switch语句与策略模式的结合
      • 多重条件的优化方法
      • 使用对象字面量替代switch语句
    • 循环语句forwhiledo...while 循环,for...infor...of
      • 各种循环的性能比较与最佳使用场景
      • for…in遍历原型链问题及防范
      • for…of与迭代器协议的关系
      • 无限循环的合理应用
    • 跳出循环breakcontinuereturn
      • 标签语句与多层循环跳出
      • continue与循环优化
      • 提前返回模式优化代码结构
  3. 函数与作用域

    • 函数声明与表达式:普通函数、匿名函数、命名函数表达式
      • 函数声明提升vs函数表达式提升
      • 立即执行函数表达式(IIFE)及其应用
      • 命名函数表达式对调试的好处
      • 高阶函数的概念与实践
    • 箭头函数:如何简化函数表达式,并理解它与普通函数的 this 指向不同
      • 箭头函数没有arguments对象的解决方案
      • 箭头函数实现对象方法的注意事项
      • 隐式返回值的各种情况
      • 何时不应使用箭头函数
    • 作用域:全局作用域、函数作用域、块级作用域
      • 词法作用域与动态作用域的区别
      • 作用域链的工作原理
      • 模块作用域在ES模块中的应用
      • eval对作用域的影响
    • 闭包:函数可以”记住”并访问定义时的作用域
      • 闭包在实际开发中的常见用例
      • 闭包导致的内存泄漏及防范
      • 工厂函数与闭包的关系
      • 闭包与模块模式
    • this:理解 this 在不同情况下的指向(例如在函数内、对象方法内、箭头函数中等)
      • call/apply/bind方法对this的影响
      • 构造函数中的this行为
      • 严格模式vs非严格模式下this的区别
      • DOM事件处理程序中的this
  4. 对象与数组

    • 对象:如何创建对象、访问属性、方法、遍历对象(如 for...in
      • 对象属性特性与Object.defineProperty
      • getter/setter方法定义与使用
      • 对象原型链与继承机制
      • Object.create与原型继承
      • 对象深拷贝与浅拷贝的实现
    • 对象解构:从对象中提取多个属性到变量
      • 嵌套解构的复杂案例
      • 解构时的默认值与重命名
      • 解构与函数参数结合使用
      • 解构失败的行为与处理
    • 数组:常用数组方法(pushpopshiftunshiftmapfilterreduce
      • 稀疏数组与密集数组的区别
      • reduce方法实现复杂数据处理
      • 数组方法链式调用与性能
      • 类数组对象转换为真数组
      • 多维数组的操作技巧
    • 数组解构:从数组中提取多个元素到变量
      • 剩余参数与数组解构结合
      • 跳过某些元素的解构方法
      • 解构赋值用于交换变量
      • 嵌套数组解构的实际应用
    • 对象与数组的迭代:如 forEachmapfilter
      • 数组方法的返回值与链式调用
      • 迭代方法中的this参数使用
      • 迭代方法与for循环的性能比较
      • 自定义迭代器实现
  5. ES6+ 新特性

    • 解构赋值:对象和数组的解构
      • 复杂嵌套解构模式
      • 解构用于API响应处理
      • 解构与默认参数结合
      • 函数参数解构的最佳实践
    • 模板字符串:使用反引号包围字符串,插入表达式
      • 标签模板函数的高级应用
      • 多行字符串处理与格式化
      • 嵌套模板字符串的处理
      • 转义序列的处理
    • 扩展运算符:用于对象和数组的合并与解构
      • 多个对象合并时的属性覆盖规则
      • 在函数参数中的应用
      • 与解构赋值结合使用
      • 实现浅拷贝的方法与限制
    • 箭头函数:简化函数声明,自动绑定 this
      • 在回调函数中的优势
      • 隐式返回对象字面量的语法
      • 不适合使用箭头函数的场景
      • 与事件处理函数结合使用
    • 类(Class):ES6 的面向对象编程,如何定义类与继承
      • 私有字段与方法(#语法)
      • 静态属性与静态方法
      • getter/setter在类中的应用
      • 继承与super关键字的使用
      • 混入模式实现多继承
    • Promise:处理异步操作的对象,如何链式调用(then/catch)以及捕获错误
      • Promise嵌套与扁平化
      • Promise.all/race/allSettled/any的区别
      • 自定义Promise实现
      • 微任务队列与事件循环的关系
    • Set 和 Map:新的数据结构,用于存储唯一值和键值对
      • WeakSet与WeakMap的特性与应用
      • 实现高效的数据去重
      • Map与Object作为字典的对比
      • Set/Map的迭代方法
    • 其他ES6+特性
      • Proxy与Reflect API的使用
      • 装饰器语法与应用(Stage 3)
      • 可选链操作符(?.)与空值合并(??)
      • 顶层await的使用(ES2022)
      • 私有类字段与方法
  6. 异步编程

    • 回调函数:理解回调的使用,及回调地狱问题
      • 错误优先回调约定
      • 异步回调与同步回调的区别
      • 实现控制流程的各种回调模式
      • 回调地狱的重构方法
    • Promise:如何创建和使用 Promise 来解决异步问题
      • Promise链中断的处理
      • 并行Promise操作的实现方法
      • Promise错误处理的最佳实践
      • 超时与竞态处理
    • async/await:通过 asyncawait 简化异步代码,使其看起来像同步代码
      • 顺序执行vs并行执行
      • 错误处理策略
      • 与Promise混合使用
      • 在循环中使用await的陷阱
    • 错误处理:如何通过 try/catch 捕获异步错误,确保代码的健壮性
      • 全局错误处理
      • 特定类型错误处理
      • 错误传播与处理策略
      • 自定义错误类型
    • 其他异步模式
      • 发布/订阅模式
      • 生成器与异步迭代
      • 可取消的异步操作
      • RxJS与响应式编程
  7. 模块化

    • 模块化引入importexport 语法,如何将代码分割到不同文件并导入使用
      • 命名导出vs默认导出
      • 动态导入与代码分割
      • 导入时重命名模块成员
      • 导入多个模块成员的模式
    • CommonJS 与 ES6 Modules:区别与使用场景
      • 两种模块系统的主要差异
      • 混合使用两种模块系统
      • Node.js中的模块解析策略
      • 循环依赖处理
    • 模块打包与构建
      • 使用Webpack/Rollup等工具
      • Tree-shaking机制
      • 代码分割与懒加载
      • 模块热替换(HMR)
    • 模块设计模式
      • 揭示模块模式
      • 单例模式与模块
      • 依赖注入
      • 模块组合与聚合
  8. 事件处理

    • 事件监听:如何在 DOM 元素上绑定事件监听器,理解事件的冒泡与捕获
      • 行内事件vs addEventListener
      • 多事件处理程序注册
      • once选项与单次触发
      • passive选项与滚动性能
    • 事件对象:如何访问事件信息(例如点击的元素、键盘按键等)
      • 常用事件属性与方法
      • 不同事件类型的特有属性
      • Event与CustomEvent的区别
      • 合成事件与原生事件
    • 事件委托:在父元素上监听事件,提高性能和代码简洁性
      • 事件委托的性能优势
      • 动态元素的事件处理
      • 复杂嵌套结构中的事件委托
      • 委托事件的过滤技术
    • 自定义事件
      • 创建与分发自定义事件
      • 事件总线/发布订阅模式
      • 跨组件通信
      • 事件命名空间
    • 事件流控制
      • 事件冒泡与捕获机制详解
      • preventDefault与stopPropagation
      • event.stopImmediatePropagation
      • 事件顺序与执行时机
  9. 错误处理与调试

    • **try...catch**:捕获并处理同步代码的错误
      • try…catch…finally的完整使用
      • 各种内置错误类型的识别
      • 错误包装与重抛出
      • 多重catch块与特定错误处理
    • 调试工具:使用浏览器的开发者工具进行调试,console.log()console.error() 等调试方法
      • 条件断点设置
      • 监视表达式与断点
      • 调用栈分析
      • 性能分析工具
      • 网络请求分析
    • 自定义错误:创建和抛出自定义错误,例如 throw new Error('message')
      • 继承Error类创建自定义错误
      • 错误层次结构设计
      • 带错误代码的错误
      • 错误本地化
    • 错误日志与监控
      • 错误上报系统
      • 生产环境错误捕获
      • 用户行为追踪
      • 异常分析与处理流程
    • 防御式编程
      • 输入验证
      • 参数类型检查
      • 边界条件测试
      • 安全错误处理
  10. 性能优化

  • 防抖与节流:减少高频事件的执行,尤其是输入框、窗口大小调整等
    • 自定义防抖函数实现
    • 自定义节流函数实现
    • 立即执行的防抖变体
    • 适合防抖与节流的场景分析
  • 懒加载:推迟不必要的资源加载,提升初始加载速度
    • 图片懒加载实现
    • 组件懒加载技术
    • Intersection Observer API应用
    • 预加载与懒加载结合
  • 内存管理:理解垃圾回收机制,避免内存泄漏(如无用的闭包、循环引用等)
    • 检测内存泄漏的工具与方法
    • 常见的内存泄漏模式
    • WeakMap/WeakSet预防内存泄漏
    • 大型应用的内存管理策略
  • 算法优化:理解时间复杂度和空间复杂度,优化循环和递归操作
    • 常见排序算法的JavaScript实现
    • 数据结构选择对性能的影响
    • 递归优化与尾调用
    • 动态规划与记忆化
  • 批量DOM操作:使用文档片段(DocumentFragment)和离线DOM操作减少重排和重绘
    • DocumentFragment优化DOM操作
    • 虚拟DOM原理
    • 最小化重排与重绘
    • requestAnimationFrame应用
  • 渲染性能
    • 硬件加速与will-change
    • 复合层与层管理
    • 高效动画实现
    • 栅格化与绘制优化
  • JavaScript执行优化
    • Web Worker多线程处理
    • 代码分割与按需加载
    • 函数去抖与节流
    • JIT优化友好的代码
  1. Web APIs与本地存储
  • localStorage 和 sessionStorage:客户端存储键值对的不同方式和使用场景
    • 存储限制与处理方法
    • 数据序列化与反序列化
    • 跨域存储访问限制
    • 存储事件与同步
  • Cookies:了解cookie的设置、读取、参数和安全性考虑
    • Cookie属性详解(HttpOnly, Secure, SameSite)
    • 第一方Cookie vs 第三方Cookie
    • Cookie安全最佳实践
    • 服务器与客户端Cookie操作
  • IndexedDB:客户端结构化数据存储,适用于大量数据存储和复杂查询
    • 数据库创建与版本管理
    • 事务与CRUD操作
    • 索引创建与高效查询
    • 异步API使用模式
  • Cache API:理解浏览器缓存机制和Service Worker配合使用
    • 缓存策略(Cache-First, Network-First等)
    • 缓存失效与更新
    • 预加载与离线访问
    • 与Service Worker集成
  • Geolocation API:获取用户位置信息
    • 位置权限管理
    • 高精度vs低功耗选项
    • 位置监视与更新
    • 错误处理与降级策略
  • Web Workers:在后台线程执行计算密集型任务,避免阻塞主线程
    • 创建与使用Worker
    • Worker间通信
    • SharedWorker与跨标签页通信
    • Worker中可用的API
  • 其他重要Web APIs
    • Fetch API与网络请求
    • Web Sockets实时通信
    • File API与本地文件操作
    • Web Audio API音频处理
    • Canvas与WebGL图形渲染
    • Drag and Drop API
  1. 现代JavaScript与最佳实践
  • 函数式编程:纯函数、不可变性和高阶函数的概念和使用
    • 纯函数概念与实践
    • 高阶函数与函数组合
    • 柯里化与偏函数应用
    • 不可变数据处理
    • 函数式编程库(Ramda, Lodash/fp)
  • 代码分割:动态导入和懒加载模块,提高应用加载性能
    • 基于路由的代码分割
    • 基于组件的代码分割
    • import()语法与webpack集成
    • 预加载与预获取技术
  • 空值处理:使用空值合并运算符(??)和可选链操作符(?.)
    • 空值合并与默认值的区别
    • 深层属性访问安全策略
    • 空值处理的模式与反模式
    • Maybe模式与Option类型
  • TypeScript基础:类型系统、接口和泛型的基本概念
    • 基本类型注解
    • 接口与类型别名
    • 泛型编程
    • TypeScript配置与集成
    • 类型声明文件(.d.ts)
  • 状态管理:了解常见的状态管理模式和原则
    • 单向数据流
    • 不可变状态原则
    • 状态容器设计
    • 发布/订阅模式
    • Context API与Redux比较
  • 测试技术:单元测试、集成测试的基本概念和工具
    • Jest, Mocha等测试框架
    • BDD vs TDD方法论
    • 测试覆盖率与质量度量
    • 模拟与存根
    • E2E测试与Cypress
  • 代码规范:了解ESLint、Prettier等工具,保持代码一致性和质量
    • 配置ESLint规则
    • Prettier代码格式化
    • Git hooks与提交前检查
    • 风格指南与团队规范
    • JSDoc文档注释
  • 设计模式与架构
    • 常用JavaScript设计模式
    • 组件化与模块化设计
    • SOLID原则应用
    • 微前端架构
    • 服务端渲染vs客户端渲染