JavaScript学习大纲
由于篇幅限制,我将简要概述每个部分的关键点,而不是详细讲解每一个知识点。如果你需要更详细的解释,可以针对每个部分提出具体问题。
1. 基础概念
- JavaScript 简介
- JavaScript 是一种脚本语言,用于创建动态和交互式的网页。
- 它可以在浏览器中运行,也可以在服务器端(Node.js)运行。
- 开发环境
- 浏览器开发工具(如 Chrome DevTools)可以帮助调试和分析代码。
- 文本编辑器(如 VSCode)或 IDE(如 WebStorm)用于编写代码。
2. 基本语法
2.1 变量和数据类型
2.1.1 变量声明
var
:var
是 JavaScript 最早的变量声明方式,存在变量提升现象。- 范例:
1
2var x = 10;
console.log(x); // 输出: 10
let
:let
是 ES6 引入的,用于声明块级作用域的变量。- 范例:
1
2let y = 20;
console.log(y); // 输出: 20
const
:const
用于声明常量,一旦赋值就不能再更改。- 范例:
1
2
3const z = 30;
console.log(z); // 输出: 30
// z = 40; // 会抛出 TypeError: Assignment to constant variable.
2.1.2 数据类型
基本数据类型:
- 字符串: 用于表示文本数据。
1
let str = "Hello, World!";
- 数字: 用于表示整数和浮点数。
1
let num = 42;
- 布尔值:
true
或false
。1
let isTrue = true;
null
: 表示空值。1
let emptyValue = null;
undefined
: 表示未定义的值。1
let undefinedValue;
Symbol
: 唯一且不可变的值,通常用于对象属性。1
let sym = Symbol('unique');
BigInt
: 用于表示大整数。1
let bigInt = 1234567890123456789012345678901234567890n;
- 字符串: 用于表示文本数据。
引用数据类型:
- 对象: 用于存储键值对。
1
let obj = { name: "Alice", age: 25 };
- 数组: 有序集合。
1
let arr = [1, 2, 3, 4, 5];
- 对象: 用于存储键值对。
2.2 运算符
2.2.1 算术运算符
- 加法(
+
):1
let sum = 5 + 3; // 8
- 减法(
-
):1
let difference = 5 - 3; // 2
- 乘法(
*
):1
let product = 5 * 3; // 15
- 除法(
/
):1
let quotient = 5 / 3; // 1.6667
- 取模(
%
):1
let remainder = 5 % 3; // 2
- 指数(
**
):1
let power = 5 ** 3; // 125
2.2.2 赋值运算符
- 赋值(
=
):1
let x = 10;
- 复合赋值运算符(如
+=
,-=
,*=
,/=
,%=
):1
2let y = 5;
y += 3; // 等同于 y = y + 3; y 现在是 8
2.2.3 比较运算符
- 等于(
==
)和全等于(===
):1
25 == '5'; // true, 因为类型转换
5 === '5'; // false, 因为不进行类型转换 - 不等于(
!=
)和全不等于(!==
):1
25 != '5'; // false, 因为类型转换后相等
5 !== '5'; // true, 因为类型不同 - 大于(
>
),小于(<
),大于等于(>=
),小于等于(<=
):1
25 > 3; // true
5 < 3; // false
2.2.4 逻辑运算符
- 逻辑与(
&&
):1
true && false; // false
- 逻辑或(
||
):1
true || false; // true
- 逻辑非(
!
):1
!true; // false
2.2.5 一元运算符和二元运算符
- 一元运算符: 只操作一个操作数。
1
2let a = 1;
a++; // 自增运算符,相当于 a = a + 1 - 二元运算符: 操作两个操作数。
1
let b = 1 + 2; // 二元加法运算符
2.3 控制流
2.3.1 条件语句
if
,else if
,else
:1
2
3
4
5
6
7
8let num = 10;
if (num > 10) {
console.log('num 大于 10');
} else if (num === 10) {
console.log('num 等于 10');
} else {
console.log('num 小于 10');
}switch
:1
2
3
4
5
6
7
8
9
10
11let color = 'red';
switch (color) {
case 'red':
console.log('The color is red');
break;
case 'blue':
console.log('The color is blue');
break;
default:
console.log('The color is not red or blue');
}
2.3.2 循环语句
for
:1
2
3for (let i = 0; i < 5; i++) {
console.log(i); // 输出 0, 1, 2, 3, 4
}while
:1
2
3
4
5let i = 0;
while (i < 5) {
console.log(i); // 输出 0, 1, 2, 3, 4
i++;
}do...while
:1
2
3
4
5let i = 0;
do {
console.log(i); // 输出 0, 1, 2, 3, 4
i++;
} while (i < 5);
2.3.3 跳转语句
break
: 立即退出循环或switch
语句。1
2
3
4
5
6for (let i = 0; i < 5; i++) {
if (i === 3) {
break; // 退出循环
}
console.log(i); // 输出 0, 1, 2
}continue
: 跳过当前循环的剩余部分,继续下一次循环。1
2
3
4
5
6for (let i = 0; i < 5; i++) {
if (i === 3) {
continue; // 跳过当前循环
}
console.log(i); // 输出 0, 1, 2, 4
}
3. 函数
3.1 函数声明和表达式
3.1.1 函数声明
- 语法:
1
2
3function functionName(parameters) {
// 函数体
} - 示例:
1
2
3
4
5function add(a, b) {
return a + b;
}
let result = add(2, 3); // 5
console.log(result);
3.1.2 函数表达式
- 语法:
1
2
3const functionName = function(parameters) {
// 函数体
}; - 示例:
1
2
3
4
5const multiply = function(a, b) {
return a * b;
};
let product = multiply(2, 3); // 6
console.log(product);
3.1.3 匿名函数
- 语法:
1
2
3const anonymousFunction = function() {
// 函数体
}; - 示例:
1
2
3
4const greet = function() {
console.log('Hello, World!');
};
greet();
3.2 高级函数概念
3.2.1 默认参数
- 语法:
1
2
3function functionName(param1 = defaultValue1, param2 = defaultValue2) {
// 函数体
} - 示例:
1
2
3
4
5function greet(name = 'Guest') {
console.log('Hello, ' + name);
}
greet(); // Hello, Guest
greet('Alice'); // Hello, Alice
3.2.2 箭头函数
- 语法:
1
2
3const functionName = (parameters) => {
// 函数体
}; - 示例:
1
2const add = (a, b) => a + b;
console.log(add(2, 3)); // 5
3.2.3 高阶函数
- 高阶函数: 接受一个或多个函数作为参数,或者返回一个函数。
- 示例:
1
2
3
4
5
6
7
8
9function higherOrderFunction(callback) {
callback();
}
function sayHello() {
console.log('Hello!');
}
higherOrderFunction(sayHello); // Hello!
3.2.4 闭包
- 闭包: 函数和其词法环境的组合,使得函数可以访问其作用域外的变量。
- 示例:
1
2
3
4
5
6
7
8
9
10
11
12function outerFunction() {
let outerVariable = 'I am outside!';
function innerFunction() {
console.log(outerVariable);
}
return innerFunction;
}
const closure = outerFunction();
closure(); // I am outside!
3.2.5 即时调用函数表达式 (IIFE)
- 语法:
1
2
3(function() {
// 函数体
})(); - 示例:
1
2
3(function() {
console.log('IIFE executed');
})();
3.3 函数参数和返回值
3.3.1 参数
- 基本参数:
1
2
3
4function add(a, b) {
return a + b;
}
console.log(add(2, 3)); // 5 - 剩余参数: 用于传递不定数量的参数。
1
2
3
4function sum(...args) {
return args.reduce((acc, val) => acc + val, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
3.3.2 返回值
- 基本返回值:
1
2
3
4function multiply(a, b) {
return a * b;
}
console.log(multiply(2, 3)); // 6 - 多个返回值: 可以使用数组或对象返回多个值。
1
2
3
4
5function getCoordinates() {
return { x: 10, y: 20 };
}
const coordinates = getCoordinates();
console.log(coordinates.x, coordinates.y); // 10 20
3.4 函数作用域和上下文
3.4.1 作用域
- 局部作用域: 在函数内声明的变量只能在函数内访问。
1
2
3
4
5
6function localScope() {
let localVar = 'I am local';
console.log(localVar);
}
localScope(); // I am local
// console.log(localVar); // Uncaught ReferenceError: localVar is not defined - 全局作用域: 在函数外声明的变量可以在整个程序中访问。
1
2
3
4
5let globalVar = 'I am global';
function accessGlobalVar() {
console.log(globalVar);
}
accessGlobalVar(); // I am global
3.4.2 上下文(this
关键字)
- 全局上下文:
this
指向全局对象(浏览器中是window
)。1
console.log(this); // Window
- 函数上下文: 在函数内
this
指向调用该函数的对象。1
2
3
4
5
6
7const obj = {
value: 42,
getValue: function() {
return this.value;
}
};
console.log(obj.getValue()); // 42
3.5 函数的其他高级用法
3.5.1 函数柯里化(Currying)
- 函数柯里化: 将接受多个参数的函数转换为接受一个参数的函数,并返回一个新的函数。
- 示例:
1
2
3
4
5
6
7function curryFunction(a) {
return function(b) {
return a + b;
};
}
const addFive = curryFunction(5);
console.log(addFive(3)); // 8
3.5.2 函数组合(Function Composition)
- 函数组合: 将多个函数组合成一个新的函数,每个函数的输出作为下一个函数的输入。
- 示例:
1
2
3
4
5const compose = (f, g) => (x) => f(g(x));
const addOne = (num) => num + 1;
const double = (num) => num * 2;
const addOneAndDouble = compose(double, addOne);
console.log(addOneAndDouble(5)); // 12
3.6 函数式编程(Functional Programming)
- 纯函数: 不依赖外部状态且不改变外部状态的函数。
- 高阶函数: 接受函数作为参数或返回函数的函数。
- 示例:
1
2
3
4
5
6
7
8
9
10
11const pureAdd = (a, b) => a + b;
const map = (arr, fn) => {
let result = [];
for (let i = 0; i < arr.length; i++) {
result.push(fn(arr[i]));
}
return result;
};
const numbers = [1, 2, 3, 4];
const doubledNumbers = map(numbers, (num) => num * 2);
console.log(doubledNumbers); // [2, 4, 6, 8]
4. 对象和数组
4.1 对象
4.1.1 对象的创建
- 对象字面量:
1
2
3
4
5
6
7const person = {
name: 'Alice',
age: 25,
greet: function() {
console.log('Hello, ' + this.name);
}
}; - 构造函数:
1
2
3
4
5
6
7
8
9
10
11function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greet = function() {
console.log('Hello, ' + this.name);
};
const bob = new Person('Bob', 30);
bob.greet(); // Hello, Bob Object.create
方法:1
2
3
4
5
6
7
8
9const proto = {
greet: function() {
console.log('Hello, ' + this.name);
}
};
const charlie = Object.create(proto);
charlie.name = 'Charlie';
charlie.greet(); // Hello, Charlie
4.1.2 对象的属性访问和操作
- 访问属性:
1
2console.log(person.name); // Alice
console.log(person['age']); // 25 - 添加属性:
1
2person.job = 'Engineer';
console.log(person.job); // Engineer - 删除属性:
1
2delete person.age;
console.log(person.age); // undefined - 检查属性:
1
2console.log('name' in person); // true
console.log(person.hasOwnProperty('age')); // false
4.1.3 对象方法
- 基本方法:
1
2
3
4
5
6
7const person = {
name: 'Alice',
greet: function() {
console.log('Hello, ' + this.name);
}
};
person.greet(); // Hello, Alice - ES6 简写方法:
1
2
3
4
5
6
7const person = {
name: 'Alice',
greet() {
console.log('Hello, ' + this.name);
}
};
person.greet(); // Hello, Alice
4.1.4 对象的遍历
for...in
循环:1
2
3
4
5for (let key in person) {
if (person.hasOwnProperty(key)) {
console.log(key + ': ' + person[key]);
}
}Object.keys
方法:1
2
3
4const keys = Object.keys(person);
keys.forEach(key => {
console.log(key + ': ' + person[key]);
});Object.values
方法:1
2
3
4const values = Object.values(person);
values.forEach(value => {
console.log(value);
});Object.entries
方法:1
2
3
4const entries = Object.entries(person);
entries.forEach(([key, value]) => {
console.log(key + ': ' + value);
});
4.2 数组
4.2.1 数组的创建
- 数组字面量:
1
const numbers = [1, 2, 3, 4, 5];
- 构造函数:
1
const fruits = new Array('Apple', 'Banana', 'Cherry');
Array.of
方法:1
const letters = Array.of('a', 'b', 'c');
Array.from
方法:1
2const str = 'hello';
const strArray = Array.from(str); // ['h', 'e', 'l', 'l', 'o']
4.2.2 数组的操作
- 访问元素:
1
console.log(numbers[0]); // 1
- 修改元素:
1
2numbers[1] = 10;
console.log(numbers); // [1, 10, 3, 4, 5] - 添加元素:
1
2numbers.push(6);
console.log(numbers); // [1, 10, 3, 4, 5, 6] - 删除元素:
1
2numbers.pop();
console.log(numbers); // [1, 10, 3, 4, 5]
4.2.3 数组的方法
push
和pop
:1
2
3
4
5
6const stack = [];
stack.push(1);
stack.push(2);
console.log(stack); // [1, 2]
stack.pop();
console.log(stack); // [1]shift
和unshift
:1
2
3
4
5
6const queue = [];
queue.push(1);
queue.push(2);
console.log(queue); // [1, 2]
queue.shift();
console.log(queue); // [2]slice
和splice
:1
2
3
4
5
6const arr = [1, 2, 3, 4, 5];
const sliced = arr.slice(1, 3);
console.log(sliced); // [2, 3]
arr.splice(1, 2);
console.log(arr); // [1, 4, 5]concat
和join
:1
2
3
4
5
6
7const arr1 = [1, 2];
const arr2 = [3, 4];
const combined = arr1.concat(arr2);
console.log(combined); // [1, 2, 3, 4]
const joined = combined.join('-');
console.log(joined); // "1-2-3-4"
4.2.4 数组的遍历
for
循环:1
2
3for (let i = 0; i < numbers.length; i++) {
console.log(numbers[i]);
}for...of
循环:1
2
3for (let number of numbers) {
console.log(number);
}forEach
方法:1
2
3numbers.forEach(number => {
console.log(number);
});
4.2.5 数组的高级方法
map
: 创建一个新数组,包含原数组中每个元素调用提供的函数后的结果。1
2const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 20, 6, 8, 10]filter
: 创建一个新数组,包含所有通过提供的函数实现的测试的元素。1
2const evens = numbers.filter(num => num % 2 === 0);
console.log(evens); // [10, 4]reduce
: 对数组中的每个元素执行一个提供的函数,将其结果汇总为单个值。1
2const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log(sum); // 23find
: 返回数组中满足提供的测试函数的第一个元素的值。1
2const firstEven = numbers.find(num => num % 2 === 0);
console.log(firstEven); // 10some
和every
:1
2
3
4
5const hasEven = numbers.some(num => num % 2 === 0);
console.log(hasEven); // true
const allEven = numbers.every(num => num % 2 === 0);
console.log(allEven); // false
4.3 数组和对象的组合使用
- 对象数组:
1
2
3
4
5
6
7
8
9const people = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 },
{ name: 'Charlie', age: 35 }
];
people.forEach(person => {
console.log(person.name + ' is ' + person.age + ' years old');
}); - 数组对象:
1
2
3
4
5
6
7
8
9const group = {
members: ['Alice', 'Bob', 'Charlie'],
addMember(name) {
this.members.push(name);
}
};
group.addMember('Dave');
console.log(group.members); // ['Alice', 'Bob', 'Charlie', 'Dave']
5. 面向对象编程 (OOP)
5.1 基本概念
5.1.1 类和实例
- 类: 类是创建对象的蓝图,它定义了对象的属性和方法。
- 实例: 通过类创建的对象称为实例。
5.1.2 构造函数
- 构造函数: 用于初始化类的新实例。
1
2
3
4
5
6
7
8
9
10
11
12
13class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hello, my name is ${this.name}`);
}
}
const alice = new Person('Alice', 25);
alice.greet(); // Hello, my name is Alice
5.2 继承
5.2.1 基本继承
extends
关键字: 用于创建一个类,该类是另一个类的子类。1
2
3
4
5
6
7
8
9
10
11
12
13
14class Employee extends Person {
constructor(name, age, jobTitle) {
super(name, age);
this.jobTitle = jobTitle;
}
work() {
console.log(`${this.name} is working as a ${this.jobTitle}`);
}
}
const bob = new Employee('Bob', 30, 'Developer');
bob.greet(); // Hello, my name is Bob
bob.work(); // Bob is working as a Developer
5.2.2 方法重写
- 子类可以重写父类的方法,以提供特定的实现。
1
2
3
4
5
6
7
8
9
10
11
12
13class Employee extends Person {
constructor(name, age, jobTitle) {
super(name, age);
this.jobTitle = jobTitle;
}
greet() {
console.log(`Hi, I am ${this.name} and I work as a ${this.jobTitle}`);
}
}
const bob = new Employee('Bob', 30, 'Developer');
bob.greet(); // Hi, I am Bob and I work as a Developer
5.3 封装
5.3.1 公有和私有属性
- 公有属性: 可以在类的外部访问。
1
2
3
4
5
6
7
8
9class Person {
constructor(name, age) {
this.name = name; // 公有属性
this.age = age; // 公有属性
}
}
const charlie = new Person('Charlie', 35);
console.log(charlie.name); // Charlie - 私有属性: 只能在类的内部访问(ES6 中可以使用
#
来声明私有属性)。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class Person {
#privateAge; // 私有属性
constructor(name, age) {
this.name = name;
this.#privateAge = age;
}
getAge() {
return this.#privateAge;
}
}
const charlie = new Person('Charlie', 35);
console.log(charlie.getAge()); // 35
// console.log(charlie.#privateAge); // Uncaught SyntaxError: Private field '#privateAge' must be declared in an enclosing class
5.3.2 Getter 和 Setter
- Getter: 用于获取属性值的方法。
- Setter: 用于设置属性值的方法。
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
26class Person {
#age;
constructor(name, age) {
this.name = name;
this.#age = age;
}
get age() {
return this.#age;
}
set age(newAge) {
if (newAge > 0) {
this.#age = newAge;
} else {
console.log('Age must be positive');
}
}
}
const dave = new Person('Dave', 40);
console.log(dave.age); // 40
dave.age = 45;
console.log(dave.age); // 45
dave.age = -5; // Age must be positive
5.4 多态
5.4.1 方法重载
- JavaScript 不支持方法重载,但可以通过检查参数来实现类似的效果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14class Calculator {
add(a, b) {
if (typeof a === 'number' && typeof b === 'number') {
return a + b;
} else if (Array.isArray(a) && a.length && b === undefined) {
return a.reduce((acc, val) => acc + val, 0);
}
return null;
}
}
const calc = new Calculator();
console.log(calc.add(2, 3)); // 5
console.log(calc.add([1, 2, 3, 4])); // 10
5.4.2 接口和抽象类
- JavaScript 没有内建的接口和抽象类,但可以通过设计模式实现类似的功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23class Animal {
makeSound() {
throw new Error('This method must be implemented by subclass');
}
}
class Dog extends Animal {
makeSound() {
console.log('Woof Woof!');
}
}
class Cat extends Animal {
makeSound() {
console.log('Meow Meow!');
}
}
const dog = new Dog();
dog.makeSound(); // Woof Woof!
const cat = new Cat();
cat.makeSound(); // Meow Meow!
5.5 原型和继承
5.5.1 原型链
- 每个对象都有一个原型,对象可以从其原型继承属性和方法。
1
2
3
4
5
6
7
8
9
10
11function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
const emily = new Person('Emily', 28);
emily.greet(); // Hello, my name is Emily
5.5.2 Object.create
方法
- 使用
Object.create
方法可以设置一个对象的原型。1
2
3
4
5
6
7
8
9const personPrototype = {
greet() {
console.log(`Hello, my name is ${this.name}`);
}
};
const frank = Object.create(personPrototype);
frank.name = 'Frank';
frank.greet(); // Hello, my name is Frank
5.5.3 原型继承
- 可以通过原型继承实现继承关系。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22function Animal(name) {
this.name = name;
}
Animal.prototype.makeSound = function() {
console.log('Some generic sound');
};
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.makeSound = function() {
console.log('Woof Woof!');
};
const rex = new Dog('Rex', 'Labrador');
rex.makeSound(); // Woof Woof!
5.6 其他高级特性
5.6.1 静态方法
- 静态方法是属于类而不是实例的方法。
1
2
3
4
5
6
7class MathUtils {
static add(a, b) {
return a + b;
}
}
console.log(MathUtils.add(5, 3)); // 8
5.6.2 单例模式
- 单例模式确保一个类只有一个实例。
1
2
3
4
5
6
7
8
9
10
11
12
13class Singleton {
constructor() {
if (!Singleton.instance) {
Singleton.instance = this;
}
return Singleton.instance;
}
}
const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2); // true
5.6.3 混入
- 混入(Mixin)是将一个对象的属性和方法拷贝到另一个对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23const canFly = {
fly() {
console.log('Flying!');
}
};
const canSwim = {
swim() {
console.log('Swimming!');
}
};
class Animal {
constructor(name) {
this.name = name;
}
}
Object.assign(Animal.prototype, canFly, canSwim);
const bird = new Animal('Bird');
bird.fly(); // Flying!
bird.swim(); // Swimming!
好的,下面我将详细讲解 JavaScript 中的异步编程,包括回调函数、Promise、async/await 以及事件循环等概念。
6. 异步编程
6.1 回调函数
6.1.1 基本概念
- 回调函数: 作为参数传递给另一个函数,并在某个事件发生后被调用的函数。
1
2
3
4
5
6
7
8
9function fetchData(callback) {
setTimeout(() => {
callback('Data fetched');
}, 1000);
}
fetchData((data) => {
console.log(data); // Data fetched
});
6.1.2 回调地狱
- 回调地狱: 多层嵌套的回调函数,导致代码难以阅读和维护。
1
2
3
4
5
6
7fetchData1((data1) => {
fetchData2(data1, (data2) => {
fetchData3(data2, (data3) => {
console.log(data3);
});
});
});
6.2 Promise
6.2.1 基本概念
- Promise: 表示一个异步操作的最终完成(或失败)及其结果值的对象。
1
2
3
4
5
6
7
8
9
10
11function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Data fetched');
}, 1000);
});
}
fetchData().then((data) => {
console.log(data); // Data fetched
});
6.2.2 链式调用
- 链式调用: 通过
.then
方法链式调用多个异步操作。1
2
3
4
5
6fetchData1()
.then((data1) => fetchData2(data1))
.then((data2) => fetchData3(data2))
.then((data3) => {
console.log(data3);
});
6.2.3 错误处理
- 错误处理: 使用
.catch
方法捕获和处理错误。1
2
3
4
5
6
7fetchData()
.then((data) => {
console.log(data);
})
.catch((error) => {
console.error(error);
});
6.3 async/await
6.3.1 基本概念
- async/await: 一种更简洁的异步编程语法,使得异步代码看起来像同步代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14async function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Data fetched');
}, 1000);
});
}
async function main() {
const data = await fetchData();
console.log(data); // Data fetched
}
main();
6.3.2 错误处理
- 错误处理: 使用
try/catch
块捕获和处理错误。1
2
3
4
5
6
7
8
9
10async function main() {
try {
const data = await fetchData();
console.log(data);
} catch (error) {
console.error(error);
}
}
main();
6.3.3 并行执行
- 并行执行: 使用
Promise.all
并行执行多个异步操作。1
2
3
4
5
6async function main() {
const [data1, data2] = await Promise.all([fetchData1(), fetchData2()]);
console.log(data1, data2);
}
main();
6.4 事件循环
6.4.1 基本概念
- 事件循环: JavaScript 运行时环境(如浏览器和 Node.js)处理异步操作的机制。
- 调用栈: 执行同步代码。
- 任务队列: 存放异步回调函数。
- 微任务队列: 存放 Promise 回调函数。
6.4.2 执行顺序
- 执行顺序: 事件循环的执行顺序是先执行调用栈中的同步代码,然后执行微任务队列中的任务,最后执行任务队列中的任务。
1
2
3
4
5
6
7
8
9
10
11
12
13console.log('Start');
setTimeout(() => {
console.log('Timeout');
}, 0);
Promise.resolve().then(() => {
console.log('Promise');
});
console.log('End');
// 输出顺序: Start -> End -> Promise -> Timeout
6.5 高级异步模式
6.5.1 生成器 (Generators)
- 生成器: 一种可以暂停和恢复执行的函数。
1
2
3
4
5
6
7
8
9
10function* generateNumbers() {
let i = 0;
while (true) {
yield i++;
}
}
const generator = generateNumbers();
console.log(generator.next().value); // 0
console.log(generator.next().value); // 1
6.5.2 异步生成器
- 异步生成器: 结合生成器和异步编程。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17async function* fetchData() {
let page = 1;
while (true) {
const data = await fetch(`https://api.example.com/data?page=${page}`);
yield data;
page++;
}
}
async function main() {
const generator = fetchData();
for await (const data of generator) {
console.log(data);
}
}
main();
6.5.3 异步迭代器
- 异步迭代器: 用于迭代异步数据源。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19const asyncIterable = {
[Symbol.asyncIterator]() {
let i = 0;
return {
next() {
if (i < 3) {
return Promise.resolve({ value: i++, done: false });
}
return Promise.resolve({ done: true });
}
};
}
};
(async function() {
for await (const num of asyncIterable) {
console.log(num);
}
})();
好的,下面我将详细讲解 JavaScript 在浏览器环境中的运行机制、DOM 操作、事件处理、Web API 以及性能优化等方面的内容。
7. 浏览器环境
7.1 浏览器运行机制
7.1.1 JavaScript 引擎
- JavaScript 引擎: 浏览器中的 JavaScript 引擎(如 V8、SpiderMonkey、JavaScriptCore)负责解析和执行 JavaScript 代码。
- V8: Chrome 和 Node.js 使用的引擎。
- SpiderMonkey: Firefox 使用的引擎。
- JavaScriptCore: Safari 使用的引擎。
7.1.2 渲染引擎
- 渲染引擎: 负责将 HTML、CSS 和 JavaScript 转换为可视化的网页。
- Blink: Chrome 和 Opera 使用的渲染引擎。
- Gecko: Firefox 使用的渲染引擎。
- WebKit: Safari 使用的渲染引擎。
7.1.3 事件循环
- 事件循环: 浏览器中的事件循环负责处理异步事件,确保 JavaScript 代码的执行顺序。
- 调用栈: 执行同步代码。
- 任务队列: 存放异步回调函数。
- 微任务队列: 存放 Promise 回调函数。
7.2 DOM 操作
7.2.1 基本概念
- DOM (Document Object Model): 文档对象模型,是 HTML 和 XML 文档的编程接口。
1
2const element = document.getElementById('myElement');
console.log(element.textContent);
7.2.2 选择元素
- 选择元素: 使用各种方法选择 DOM 元素。
1
2
3
4
5const elementById = document.getElementById('myId');
const elementsByClass = document.getElementsByClassName('myClass');
const elementsByTag = document.getElementsByTagName('div');
const elementByQuery = document.querySelector('#myId');
const elementsByQuery = document.querySelectorAll('.myClass');
7.2.3 修改元素
- 修改元素: 修改 DOM 元素的内容和样式。
1
2
3const element = document.getElementById('myElement');
element.textContent = 'New Text';
element.style.color = 'red';
7.2.4 创建和删除元素
- 创建和删除元素: 动态创建和删除 DOM 元素。
1
2
3
4
5
6const newElement = document.createElement('div');
newElement.textContent = 'New Element';
document.body.appendChild(newElement);
const oldElement = document.getElementById('oldElement');
oldElement.parentNode.removeChild(oldElement);
7.3 事件处理
7.3.1 基本概念
- 事件处理: 响应用户的交互操作(如点击、滚动、键盘输入等)。
1
2
3
4const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log('Button clicked');
});
7.3.2 事件传播
- 事件传播: 事件在 DOM 树中的传播方式(捕获阶段、目标阶段、冒泡阶段)。
1
2
3
4
5
6
7
8
9
10const parent = document.getElementById('parent');
const child = document.getElementById('child');
parent.addEventListener('click', () => {
console.log('Parent clicked');
}, true); // 捕获阶段
child.addEventListener('click', () => {
console.log('Child clicked');
}); // 冒泡阶段
7.3.3 事件委托
- 事件委托: 利用事件冒泡机制,将事件处理程序绑定到父元素,减少内存消耗。
1
2
3
4
5
6const list = document.getElementById('myList');
list.addEventListener('click', (event) => {
if (event.target.tagName === 'LI') {
console.log('List item clicked');
}
});
7.4 Web API
7.4.1 定时器
- 定时器: 使用
setTimeout
和setInterval
执行延迟或周期性任务。1
2
3
4
5
6
7setTimeout(() => {
console.log('Timeout');
}, 1000);
setInterval(() => {
console.log('Interval');
}, 1000);
7.4.2 网络请求
- 网络请求: 使用
fetch
或XMLHttpRequest
进行网络请求。1
2
3
4
5
6
7
8
9
10
11
12
13
14fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
console.log(data);
});
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data');
xhr.onload = () => {
if (xhr.status === 200) {
console.log(JSON.parse(xhr.responseText));
}
};
xhr.send();
7.4.3 存储
- 存储: 使用
localStorage
和sessionStorage
进行数据存储。1
2
3
4
5
6
7localStorage.setItem('key', 'value');
const value = localStorage.getItem('key');
console.log(value); // value
sessionStorage.setItem('key', 'value');
const sessionValue = sessionStorage.getItem('key');
console.log(sessionValue); // value
7.5 性能优化
7.5.1 减少重绘和回流
- 重绘和回流: 减少 DOM 操作,使用
DocumentFragment
或requestAnimationFrame
。1
2
3
4
5
6
7
8
9
10
11
12const fragment = document.createDocumentFragment();
for (let i = 0; i < 10; i++) {
const div = document.createElement('div');
fragment.appendChild(div);
}
document.body.appendChild(fragment);
function animate() {
// 动画逻辑
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
7.5.2 使用事件委托
- 事件委托: 减少事件处理程序的数量,提高性能。
1
2
3
4
5
6const list = document.getElementById('myList');
list.addEventListener('click', (event) => {
if (event.target.tagName === 'LI') {
console.log('List item clicked');
}
});
7.5.3 异步加载 JavaScript
- 异步加载 JavaScript: 使用
async
和defer
属性异步加载脚本。1
2<script src="script.js" async></script>
<script src="script.js" defer></script>
7.5.4 代码分割和懒加载
- 代码分割和懒加载: 使用 Webpack 等工具进行代码分割,实现懒加载。
1
2
3import('./module.js').then(module => {
module.default();
});
模块化是在现代JavaScript开发中非常重要的一个概念,主要是为了解决代码维护、命名空间、重用等问题。以下是模块化在JavaScript中的详细讲解。
8. 模块化
8.1 基本概念
8.1.1 模块的意义
- 封装: 将代码封装成独立的单元,每个模块只负责一部分功能。
- 命名空间: 每个模块提供自己的作用域,以避免全局命名冲突。
- 重用性: 模块可被多处重用,减少代码重复。
- 依赖管理: 模块化提供了一种清晰的方式来表达和管理依赖关系。
8.2 CommonJS 和 AMD
8.2.1 CommonJS
- CommonJS: 主要用于服务器端,如Node.js,通过
require
来同步加载模块。1
2
3
4
5
6
7
8
9// math.js
function add(a, b) {
return a + b;
}
module.exports = { add };
// app.js
const math = require('./math');
console.log(math.add(1, 2));
8.2.2 AMD (Asynchronous Module Definition)
- AMD: 用于浏览器端的异步模块定义,代表性实现是
RequireJS
。1
2
3
4
5
6
7
8
9// 使用RequireJS
define(['dependency'], function(dependency) {
function myModuleFunction() {
return dependency.someFunction();
}
return {
myModuleFunction
};
});
8.3 ES6 模块
8.3.1 Export 和 Import
- ES6 模块: 使用
export
关键字导出模块,使用import
关键字导入模块。1
2
3
4
5
6
7
8// math.js
export function add(a, b) {
return a + b;
}
// app.js
import { add } from './math';
console.log(add(1, 2));
8.3.2 默认导出和命名导出
- 默认导出: 一个模块只能有一个默认导出。
1
2
3
4
5
6
7
8// math.js
export default function add(a, b) {
return a + b;
}
// app.js
import add from './math';
console.log(add(1, 2)); - 命名导出: 一个模块可以有多个命名导出。
1
2
3
4
5
6
7
8
9
10
11// math.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
// app.js
import { add, subtract } from './math';
console.log(subtract(add(1, 2), 1));
8.4 模块加载机制
8.4.1 同步和异步加载
- 同步加载: 模块在被导入时立即加载,常见于服务器端。
- 异步加载: 模块在需要时才加载,适合大型应用,减少初始加载时间。
8.5 构建工具和模块打包
8.5.1 Webpack
- Webpack: 模块打包器,可以将多个模块打包成一个或多个bundle,支持代码分割和懒加载。
1
2
3
4
5
6
7
8
9
10
11
12// Webpack配置文件
module.exports = {
entry: './app.js',
output: {
filename: 'bundle.js'
},
module: {
rules: [
{ test: /\.js$/, use: 'babel-loader' }
]
}
};
8.5.2 Babel
- Babel: JavaScript编译器,可以将ES6+代码转换为向后兼容的JavaScript版本,以支持旧浏览器。
1
2
3
4// Babel配置
{
"presets": ["@babel/preset-env"]
}
8.5.3 模块解析
- 模块解析: 构建工具在打包时需要解析模块路径,处理模块的导入和导出。
8.6 模块化最佳实践
8.6.1 避免全局变量
- 尽量不要在模块中定义全局变量,以避免污染全局命名空间。
8.6.2 高内聚低耦合
- 高内聚: 模块内部功能紧密相关。
- 低耦合: 模块之间依赖关系简单清晰。
8.6.3 导出和导入必要的内容
- 只导出模块的公共接口,不要导出内部实现细节。
- 只导入所需的功能,避免无用代码。
9. 错误处理与调试
- 错误类型
- JavaScript 有多种错误类型,包括语法错误、运行时错误和逻辑错误。
- 错误处理
- 使用
try
,catch
,finally
语句可以捕获和处理错误。
- 使用
- 调试技术
- 使用浏览器开发工具和
console
对象可以帮助调试代码。
- 使用浏览器开发工具和
10. 高级主题
- 正则表达式
- 正则表达式用于匹配字符串中的模式。
- 设计模式
- 设计模式是解决常见问题的最佳实践。
- 性能优化
- 性能优化包括内存管理、代码优化和延迟加载等技术。
11. 实战项目
- 项目设置
- 项目结构和版本控制(如 Git)是项目开发的基础。
- 前端框架
- React、Vue.js 和 Angular 是流行的前端框架,用于构建复杂的用户界面。
- 后端开发
- Node.js 和 Express 是常用的后端开发技术。
12. 学习资源
- 书籍推荐
- 《JavaScript 高级程序设计》和《你不知道的 JavaScript》是深入学习 JavaScript 的好书。
- 在线课程
- Codeacademy、FreeCodeCamp 和 Udemy 提供了丰富的在线课程。
- 社区与论坛
- Stack Overflow、GitHub 和 Reddit 是获取帮助和分享知识的社区。