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

【前端】【JavaScript】【总复习】四万字详解JavaScript知识体系

JavaScript 前端知识体系


📌 说明:本大纲从基础到高级、从语法到应用、从面试到实战,分层级讲解 JavaScript 的核心内容。

一、JavaScript 基础语法

1.1 基本概念

1.1.1 JavaScript 的发展史与用途
1. 发展简史
  • 1995 年:JavaScript 由 Netscape 工程师 Brendan Eich 在 10 天 内创建,最初叫 LiveScript,后更名为 JavaScript。
  • 早期用途:仅用于网页中的简单表单校验和交互动画。
  • 1997 年:被 ECMA 国际标准化组织采纳,形成 ECMAScript 标准。
  • 2009 年:Node.js 横空出世,JS 从浏览器进入服务端。
  • 2015 年:ES6(ECMAScript 2015)发布,成为 JS 的重大飞跃。
2. 现代用途

JavaScript 已不再只是“网页脚本语言”,现在几乎无所不能

  • 浏览器交互开发(HTML+CSS+JS)
  • Web 应用开发(React/Vue/Angular)
  • 服务端开发(Node.js)
  • 移动端开发(React Native)
  • 桌面应用开发(Electron)
  • 游戏开发(Pixi.js、Three.js)
  • 自动化测试、爬虫、AI 前端可视化等

🎯 一句话总结:JS 是一门“浏览器起家、全栈统治、无处不在”的语言。


1.1.2 浏览器中的 JS 与 Node.js 的区别
特性浏览器中的 JSNode.js
运行环境浏览器(Chrome、Firefox 等)服务端(基于 V8 引擎)
核心目标实现用户交互、DOM 操作搭建 Web 服务、处理后端逻辑
可访问的 APIDOM、BOM(window、document)等文件系统(fs)、网络模块(http)
模块系统ES Module(ES6后支持)CommonJS
全局对象windowglobal
适合应用场景网页开发、浏览器插件接口服务、工具脚本、构建工具等

🚀 一句话记忆:浏览器 JS 用于“看得见的交互”,Node.js 用于“看不见的服务”。


1.1.3 动态类型语言 vs 静态类型语言
1. 类型系统简介
  • 类型:变量可以表示的数据类型,例如字符串、数字、布尔值等。
  • 类型系统:语言如何检测、限制这些数据类型的规则体系。
2. 对比分析
特性动态类型语言(如 JS)静态类型语言(如 Java、C++)
声明变量不需指定类型,运行时才知道声明时必须指定类型
类型检查在运行时进行在编译阶段进行
灵活性高,变量可变类型低,但可提升可靠性
出错时间点运行时才报错编译时就能发现类型错误
开发体验快速开发,适合原型迭代安全稳定,适合大型项目
3. 示例对比
// JS - 动态类型
let x = 10;     
x = "hello";    // 合法,x 类型变为 string
// Java - 静态类型
int x = 10;
x = "hello";  // ❌ 报错,类型不匹配

💡 总结一句话:JS 是“你想放什么我都装”,Java 是“你不给我指定我不干活”。


1.2 数据类型

JavaScript 中的数据类型分为两大类:原始类型(Primitive Type)引用类型(Reference Type)


1.2.1 原始类型(7 种)

原始类型是不可变值,每个变量直接存储值本身,保存在栈内存中。

类型示例值说明
String"hello"表示文本
Number42, 3.14, NaN所有数字(包含整数和浮点数)
Booleantrue, false逻辑值
Undefinedundefined未赋值变量的默认值
Nullnull表示“无值”
SymbolSymbol("id")创建独一无二的标识符(ES6)
BigInt12345678901234567890n表示任意精度整数(ES11)

示例:

let name = "Alice";         // String
let age = 30;               // Number
let isAdmin = true;         // Boolean
let user;                   // Undefined
let empty = null;           // Null
let key = Symbol("id");     // Symbol
let bigNumber = 123456789012345678901234567890n; // BigInt

🧠 注意typeof null === "object" 是历史遗留 bug,不代表 null 是引用类型!


1.2.2 引用类型(常见 5 类)

引用类型是可变对象,变量保存的是指向值的地址(引用),保存在堆内存中。

类型示例特点
Object{name: "Tom"}万物皆对象的基础类型
Array[1, 2, 3]有序集合,索引访问
Functionfunction() {}可调用对象,函数是一等公民
Datenew Date()日期对象
RegExp/\d+/正则表达式对象

示例:

let person = { name: "Tom", age: 25 };   // Object
let numbers = [1, 2, 3];                 // Array
let greet = function() { console.log("Hi"); }; // Function
let now = new Date();                   // Date
let pattern = /\d+/;                    // RegExp

1.2.3 原始类型 vs 引用类型 对比总结
特性原始类型引用类型
存储方式栈内存,值拷贝堆内存,引用拷贝(指针)
是否可变不可变(每次修改都创建新值)可变(修改对象本身)
比较方式值比较(===)引用地址比较
复制行为复制值复制引用,多个变量指向同一对象

示例比较:

let a = 100;
let b = a;
b = 200;
console.log(a); // 100(原始类型,值独立)let obj1 = { x: 1 };
let obj2 = obj1;
obj2.x = 99;
console.log(obj1.x); // 99(引用类型,地址共享)

📌 一句话总结:原始类型像“复制粘贴”,引用类型像“共享文件夹”。


1.3 变量声明

1.3.1 varletconst 的区别
特性varletconst
声明方式ES5,函数级作用域ES6,块级作用域ES6,块级作用域
变量提升✅ 有提升,值为 undefined✅ 有提升但不初始化✅ 有提升但不初始化
允许重复声明✅ 允许❌ 报错❌ 报错
可重新赋值✅ 可以✅ 可以❌ 不可重新赋值
是否必须初始化❌ 不需要❌ 不需要✅ 必须初始化

示例:

// var
console.log(a); // undefined(已提升)
var a = 10;// let
console.log(b); // ReferenceError(暂时性死区)
let b = 20;// const
const c = 30;
c = 40; // ❌ 报错,不能重新赋值

🔒 记忆口诀var 会提升,let 会保护,const 定值不可改。


1.3.2 作用域与变量提升(Hoisting)
  • 函数作用域(Function Scope)var 声明的变量只在函数内部有效。
  • 块级作用域(Block Scope)letconst 声明的变量只在当前代码块 {} 内有效。
function test() {if (true) {var x = 10;let y = 20;}console.log(x); // ✅ 输出 10console.log(y); // ❌ 报错
}
  • 变量提升(Hoisting):JavaScript 在运行前会“预处理”变量和函数声明,使它们“看起来”被提升到作用域顶部。
console.log(a); // undefined
var a = 5;

1.4 运算符与表达式

1.4.1 算术、比较、逻辑运算符
  • 算术运算符+ - * / % **
  • 比较运算符> < >= <= == === != !==
  • 逻辑运算符&& || !
2 ** 3     // 8,幂运算
3 > 2      // true
true && false // false

1.4.2 其他运算符
  • 三元运算符条件 ? 值1 : 值2
let result = score >= 60 ? "及格" : "不及格";
  • 位运算符& | ^ ~ << >>
    (适用于底层优化,如权限控制、性能压缩)
  • 空值合并运算符(??:仅在左值为 nullundefined 时使用右值。
let name = userName ?? "默认用户";

1.5 流程控制

1.5.1 条件判断
  • if…else
if (score >= 90) {console.log("优秀");
} else if (score >= 60) {console.log("及格");
} else {console.log("不及格");
}
  • switch…case
let color = "green";
switch (color) {case "red":console.log("红色");break;case "green":console.log("绿色");break;default:console.log("未知颜色");
}

1.5.2 循环结构
  • for 循环
for (let i = 0; i < 3; i++) {console.log(i);
}
  • while / do…while
let i = 0;
while (i < 3) {console.log(i);i++;
}do {console.log(i);i--;
} while (i > 0);
  • for…in:遍历对象的
let obj = { a: 1, b: 2 };
for (let key in obj) {console.log(key);      // "a", "b"
}
  • for…of:遍历可迭代对象的(如数组、字符串)
for (let value of [10, 20, 30]) {console.log(value);    // 10, 20, 30
}

🔁 记忆总结

  • for...in 用来遍历“对象键名”,
  • for...of 用来遍历“数组值”。

二、函数与作用域

2.1 函数定义方式


2.1.1 函数声明(Function Declaration)
function sayHi(name) {return `Hello, ${name}`;
}
  • 支持提升:可以在函数声明之前调用
  • 语义清晰,适合通用工具函数
  • 📌 函数体内 this 指向调用者
greet(); // ✅ 输出 "Hi there!"function greet() {console.log("Hi there!");
}

2.1.2 函数表达式(Function Expression)
const sayHi = function(name) {return `Hello, ${name}`;
};
  • 不支持提升:调用必须在定义之后
  • 更灵活:可作为参数传递、闭包使用
  • 命名 or 匿名:支持匿名函数
// 报错:Cannot access 'greet' before initialization
greet();const greet = function () {console.log("Hello");
};

2.1.3 箭头函数(Arrow Function)
const sayHi = (name) => {return `Hello, ${name}`;
};
  • 语法简洁
  • 没有自己的 thisarguments
  • 不能当构造函数使用

简写形式(单参数、单表达式可省略括号与 return):

const double = x => x * 2;

this 对比示例:

const obj = {normal: function() {console.log(this); // 指向 obj},arrow: () => {console.log(this); // 指向定义时外部的 this(可能是 window 或 undefined)}
};

🧠 一图记忆

类型是否提升是否有 this是否能 new是否简洁
函数声明
函数表达式
箭头函数❌(继承)✅✅✅

2.2 作用域与闭包


2.2.1 词法作用域(Lexical Scope)

定义:词法作用域是指变量的作用范围由代码书写位置决定,而非函数的调用方式。

function outer() {const a = 10;function inner() {console.log(a); // 可以访问 a}inner();
}
outer();
  • 📌 函数定义在哪里,就决定了它能访问哪些变量。
  • ✅ 内部函数可以访问其外部函数作用域中的变量,这就是闭包的基础。

💡 记忆口诀:作用域查找看“定义位置”,不是“调用位置”。


2.2.2 闭包原理与应用场景
📘 什么是闭包?

闭包(Closure)是函数与其词法环境的组合。当函数在其定义的作用域外被调用时,它仍然能够记住并访问其定义时的作用域链

function createCounter() {let count = 0;return function () {count++;return count;};
}const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
  • 🔁 count 没有被销毁,因为返回的函数一直引用它,这就是闭包。
  • 💡 JS 的函数是一等对象,可以被返回、赋值、传参,而闭包能让这些函数带上“记忆”。

📌 闭包的常见应用场景
场景示例
数据私有封装内部变量不暴露到全局作用域
函数工厂动态生成具有“私有数据”的函数
防抖节流利用闭包保存定时器引用等状态
记忆函数缓存函数执行结果(Memoization)
// 数据私有:模拟私有变量
function Secret() {let secret = "密码123";return {get: () => secret,set: (val) => secret = val};
}
const s = Secret();
console.log(s.get()); // 密码123

🧠 一句话总结:闭包 = 函数 + 定义时的作用域链,是 JS 中实现“私有状态”和“记忆能力”的核心机制。


2.3 this 指向与 call/apply/bind


2.3.1 this 在不同上下文的指向规则

this 在 JavaScript 中非常灵活,它的指向是动态的,依赖于函数的调用方式。我们可以将它分为几种主要的调用方式进行分类讲解。


一、隐式绑定(Implicit Binding)

隐式绑定指的是 在对象的方法中调用函数时,this 指向调用该方法的对象

const person = {name: "Alice",greet() {console.log(this.name);}
};
person.greet(); // "Alice"
  • 在这个例子中,this 指向 person 对象。

二、显式绑定(Explicit Binding)

显式绑定是通过 callapplybind 等方法显式地指定 this 的指向

  1. call():立即调用函数,传入 this 指定的对象和后续参数。

    function greet() {console.log(`Hello, ${this.name}`);
    }
    const person = { name: "Bob" };
    greet.call(person); // "Hello, Bob"
    
  2. apply():类似 call(),但接收一个数组作为参数。

    greet.apply(person); // "Hello, Bob"
    
  3. bind():返回一个新函数,绑定了 this,但不立即执行。

    const boundGreet = greet.bind(person);
    boundGreet(); // "Hello, Bob"
    
  • 总结callapply 立即执行,而 bind 返回一个新的函数。

三、默认绑定(Default Binding)

当函数被直接调用(例如普通函数调用时),this 的默认指向规则会根据执行环境有所不同:

  • 非严格模式下,this 会指向全局对象(浏览器中是 window,Node 中是 global)。
  • 严格模式下,thisundefined
function greet() {console.log(this);
}greet(); // 在非严格模式下,指向 window;严格模式下,指向 undefined

四、构造函数绑定(Constructor Binding)

当函数作为构造函数通过 new 关键字调用时,this 会指向新创建的实例对象。

function Person(name) {this.name = name;
}const person1 = new Person("Alice");
console.log(person1.name); // "Alice"
  • new 关键字使得 this 指向新创建的实例对象。

五、箭头函数(Arrow Function)

箭头函数没有自己的 this,它会继承外层上下文的 this。也就是说,箭头函数的 this 是在定义时就确定的,而不是在调用时确定。

const obj = {name: "Alice",greet() {const arrowFunc = () => {console.log(this.name);};arrowFunc(); // "Alice"}
};obj.greet(); // "Alice"
  • arrowFuncthis 指向的是外部的 greet 方法中的 this,即 obj

🎯 总结

调用方式this 指向
隐式绑定调用方法的对象
显式绑定callapplybind 参数指定的对象
默认绑定非严格模式下为 window,严格模式下为 undefined
构造函数绑定新创建的对象(实例)
箭头函数继承外部作用域的 this

2.3.2 手动改变 this 指向的方法

有三个方法可以手动改变函数内部的 this 指向


🧩 1)call()

立即调用函数,传入第一个参数作为 this,后续参数依次传给函数本体。

function greet(who) {console.log(`Hello, ${who}, from ${this.name}`);
}
const person = { name: "Alice" };
greet.call(person, "Bob"); // Hello, Bob, from Alice

🧩 2)apply()

call 类似,但参数必须用数组传入:

greet.apply(person, ["Charlie"]); // Hello, Charlie, from Alice

🧩 3)bind()

不会立即调用,而是返回一个新的函数,绑定了 this

const boundGreet = greet.bind(person, "Diana");
boundGreet(); // Hello, Diana, from Alice

🎯 对比总结

方法是否立即执行参数传递方式返回值
call✅ 是普通参数列表函数执行结果
apply✅ 是参数数组函数执行结果
bind❌ 否参数列表(可预设)新函数

🧠 记忆口诀
call 马上叫、apply 数组搞、bind 等你叫。


三、对象与原型链

3.1 对象创建与属性操作

3.1.1 对象的创建方式
  1. 字面量法
    使用大括号 {} 直接定义对象,简单直观。

    const person = {name: "Alice",age: 30
    };
    
  2. 构造函数法
    使用 new Object() 或通过自定义构造函数创建对象。

    const person = new Object();
    person.name = "Bob";
    person.age = 25;
    
  3. Object.create()
    使用指定的原型对象创建一个新对象,适用于原型链继承。

    const personProto = {greet() {console.log(`Hello, ${this.name}`);}
    };const person = Object.create(personProto);
    person.name = "Charlie";
    person.greet(); // Hello, Charlie
    
  4. class 关键字
    使用 ES6 中的 class 语法创建对象及其构造函数。

    class Person {constructor(name, age) {this.name = name;this.age = age;}
    }
    const person = new Person("David", 28);
    

3.1.2 属性描述符与 Object.defineProperty()

属性描述符定义了对象属性的特性(如是否可写、可枚举等)。

  • 数据描述符:包含 valuewritable(是否可修改)。
  • 访问器描述符:包含 getset

Object.defineProperty() 方法允许你直接设置属性的描述符,并能够控制属性的行为(例如是否能修改、是否能枚举等)。

const person = {};
Object.defineProperty(person, "name", {value: "Eve",writable: false,    // 不可修改enumerable: true,   // 可枚举configurable: true  // 可配置
});console.log(person.name); // Eve
person.name = "John";    // 不会修改
console.log(person.name); // Eve
  • writable: false 使得 name 属性不可修改。
  • configurable: false 防止删除该属性或修改其特性。

3.2 原型与原型链

3.2.1 __proto__ vs prototype
  1. prototype
    每个函数对象都有一个 prototype 属性,指向该函数的原型对象。构造函数的实例会继承该原型对象上的属性和方法。

    function Person(name) {this.name = name;
    }const person = new Person("Alice");
    console.log(person.__proto__ === Person.prototype); // true
    
  2. __proto__
    __proto__ 是每个对象的内部属性,指向该对象的构造函数的原型对象。它指示了对象的原型链的“父级”。

    const obj = {};
    console.log(obj.__proto__ === Object.prototype); // true
    
  • prototype 是函数的属性,而 __proto__ 是对象的属性。

3.2.2 原型链查找机制

当访问对象的属性时,JS 引擎会先在对象自身查找,如果没有找到,再沿着原型链向上查找,直到找到该属性或到达 null 为止。

  • 每个对象都有一个 __proto__ 属性,它指向该对象的构造函数的原型对象。
  • 原型对象也有 __proto__,形成一个链条,最终链条的尽头是 Object.prototype,它的 __proto__null
const obj = { name: "Alice" };
console.log(obj.name); // "Alice"
console.log(obj.toString()); // 调用 Object.prototype.toString
  • obj 没有 toString 方法,它会向原型链上的 Object.prototype 查找 toString 方法。

3.3 继承方式

3.3.1 ES5 原型继承

在 ES5 中,原型继承是通过构造函数和 prototype 属性实现的。基本的继承方式是通过让子类的 prototype 指向父类的 prototype

function Animal(name) {this.name = name;
}Animal.prototype.sayHello = function() {console.log(`Hello, I am a ${this.name}`);
};function Dog(name) {Animal.call(this, name); // 继承属性
}Dog.prototype = Object.create(Animal.prototype); // 继承方法
Dog.prototype.constructor = Dog; // 修复构造函数指向const dog = new Dog("Buddy");
dog.sayHello(); // Hello, I am a Buddy
  • Object.create() 用于创建一个新的对象,将原型链指向父类的原型对象,从而实现继承。
3.3.2 组合继承

组合继承(又叫伪经典继承)是 构造函数继承原型继承 的组合,它解决了原型继承的缺点:子类会继承父类的所有实例属性,但每个子类实例都会重复父类的实例属性。

function Animal(name) {this.name = name;
}Animal.prototype.sayHello = function() {console.log(`Hello, I am a ${this.name}`);
};function Dog(name, breed) {Animal.call(this, name); // 继承实例属性this.breed = breed;
}Dog.prototype = new Animal(); // 继承方法
Dog.prototype.constructor = Dog;const dog = new Dog("Buddy", "Golden Retriever");
dog.sayHello(); // Hello, I am a Buddy
console.log(dog.breed); // Golden Retriever
  • 缺点:构造函数 Animal.call(this) 被调用了两次。new Animal() 会创建父类的实例,并将父类的属性赋给子类原型。
3.3.3 类似寄生继承的方式

寄生继承 是通过 借用构造函数 的方式继承父类的属性,但不改变原型链。

function Animal(name) {this.name = name;
}Animal.prototype.sayHello = function() {console.log(`Hello, I am a ${this.name}`);
};function Dog(name, breed) {Animal.call(this, name); // 继承属性this.breed = breed;
}Dog.prototype = Object.create(Animal.prototype); // 继承方法
Dog.prototype.constructor = Dog;const dog = new Dog("Buddy", "Golden Retriever");
dog.sayHello(); // Hello, I am a Buddy
console.log(dog.breed); // Golden Retriever
  • 这个方式在继承父类方法时,依然保持了父类原型链的正确性,解决了构造函数重复调用的问题。
3.3.4 寄生组合继承

寄生组合继承(parasitic combination inheritance)是一种优化的方式,它结合了 寄生继承组合继承 的优点。通过 Object.create() 继承父类的方法,并通过构造函数继承父类的实例属性,避免了重复调用父类构造函数。

function Animal(name) {this.name = name;
}Animal.prototype.sayHello = function() {console.log(`Hello, I am a ${this.name}`);
};function Dog(name, breed) {Animal.call(this, name); // 继承属性this.breed = breed;
}// 使用寄生组合继承来避免重复调用父类构造函数
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;const dog = new Dog("Buddy", "Golden Retriever");
dog.sayHello(); // Hello, I am a Buddy
console.log(dog.breed); // Golden Retriever
  • 优化点:只调用一次父类的构造函数,通过 Object.create() 来继承父类的原型方法,避免了组合继承的性能问题。
3.3.5 ES6 class 继承 (extendssuper)

ES6 引入了 classextends 语法,使得继承更加简洁和直观。super 用于调用父类的构造函数或方法。

class Animal {constructor(name) {this.name = name;}sayHello() {console.log(`Hello, I am a ${this.name}`);}
}class Dog extends Animal {constructor(name, breed) {super(name); // 调用父类构造函数this.breed = breed;}bark() {console.log("Woof!");}
}const dog = new Dog("Buddy", "Golden Retriever");
dog.sayHello(); // Hello, I am a Buddy
dog.bark();     // Woof!
  • extends 用于实现继承。
  • super 用于调用父类的构造函数或方法。

3.3 总结

继承方式描述优缺点
原型继承通过设置子类原型为父类原型的实例来实现继承缺点:父类实例属性会被所有子类实例共享
组合继承结合构造函数继承和原型继承缺点:构造函数被调用两次
寄生继承通过借用构造函数继承父类实例属性,不改变原型适用于不需要创建新对象的场景
寄生组合继承结合了寄生继承与组合继承的优点,优化了性能解决了组合继承的缺点,避免了重复调用构造函数
ES6 class使用 classextends 语法简化继承语法简洁,易于理解,但仍然是基于原型链的继承

四、数组与内置对象

4.1 数组操作

4.1.1 创建与转换
方法返回值是否修改原数组作用
Array.of(...items)新数组(包含所有参数)创建一个包含所有参数的数组
Array.from(obj)新数组(类数组转数组)将类数组或可迭代对象转换为数组
arr.toString()字符串(元素用逗号连接)将数组元素转换为字符串,用逗号分隔
arr.join(sep)字符串(自定义分隔符)将数组元素连接成字符串,使用指定的分隔符

4.1.2 增删元素
方法返回值是否修改原数组作用
push(...items)新长度在数组末尾添加一个或多个元素
pop()被删除的元素删除并返回数组的最后一个元素
unshift(...items)新长度在数组开头添加一个或多个元素
shift()被删除的元素删除并返回数组的第一个元素
splice(start, del, ...items)被删除的元素数组从指定位置删除指定数量的元素,并可以插入新元素
slice(start, end)新数组(部分元素)返回数组的一个浅拷贝(部分)

4.1.3 查找与过滤
方法返回值是否修改原数组作用
indexOf(item)首个匹配索引(-1 表示不存在)查找元素首次出现的位置
lastIndexOf(item)最后匹配索引(-1 表示不存在)查找元素最后一次出现的位置
includes(item)布尔值(是否包含)判断数组是否包含某个元素
find(fn)首个匹配元素(undefined 表示不存在)查找并返回第一个满足条件的元素
findIndex(fn)首个匹配索引(-1 表示不存在)查找并返回第一个满足条件的元素索引
filter(fn)新数组(所有匹配元素)返回一个包含所有满足条件元素的新数组

4.1.4 遍历与转换
方法返回值是否修改原数组作用
forEach(fn)undefined否(但可修改元素)遍历数组,执行给定的函数,适用于副作用操作
map(fn)新数组(每个元素处理后)返回一个新的数组,每个元素经过给定函数处理
flat(depth)新数组(扁平化后)将嵌套的数组结构“拉平”至指定深度
flatMap(fn)新数组(先 map 再 flat)先对数组进行 map 操作,再进行扁平化

4.1.5 排序与反转
方法返回值是否修改原数组作用
sort(fn)原数组(排序后)对数组进行排序,默认按字符顺序排列
reverse()原数组(反转后)将数组元素的顺序颠倒

4.1.6 合并与拆分
方法返回值是否修改原数组作用
concat(...arrays)新数组(合并后)合并多个数组或值到一个新数组
split(sep)字符串 → 数组否(操作字符串)将字符串分割为数组
join(sep)数组 → 字符串将数组元素连接成一个字符串,使用指定的分隔符

4.1.7 归约方法
方法返回值是否修改原数组作用
reduce(fn, init)累计值对数组元素执行累加操作,返回累计值
reduceRight(fn, init)累计值(从右到左)从右到左对数组元素执行累加操作,返回累计值

4.1.8 判定方法
方法返回值是否修改原数组作用
every(fn)布尔值(所有元素满足)判断数组中的每个元素是否都满足条件
some(fn)布尔值(至少一个满足)判断数组中是否至少有一个元素满足条件
isArray(value)布尔值(是否为数组)否(静态方法)判断给定值是否为数组

4.1.9 其他方法
方法返回值是否修改原数组作用
fill(value, start, end)原数组(填充后)用指定的值填充数组的某部分元素
copyWithin(target, start, end)原数组(复制后)将数组中的一部分复制到同一数组的指定位置
entries()迭代器(索引-值对)返回一个数组的遍历器对象,包含索引和对应值
keys()迭代器(索引)返回一个包含数组索引的遍历器对象
values()迭代器(值)返回一个包含数组值的遍历器对象

记忆技巧

  1. 修改原数组的方法
    push/pop/unshift/shift/splice/sort/reverse/fill/copyWithin
    (口诀:增删改查排序反转填充复制
  2. 返回新数组的方法
    slice/map/filter/concat/flat/flatMap
    (口诀:切片映射过滤合并扁平化
  3. 归约与判定
    reduce/every/some/find/findIndex/includes
    (口诀:累计判定查找包含

4.2 常用内置对象

4.2.1 String 对象
1. 字符操作
方法返回值作用
charAt(index)字符返回指定位置的字符
charCodeAt(index)数字返回指定位置字符的 Unicode 编码
codePointAt(index)数字返回指定位置字符的 Unicode 代码点
fromCharCode(...codes)字符串从 Unicode 编码返回字符
fromCodePoint(...codePoints)字符串从 Unicode 代码点返回字符
2. 查找与替换
方法返回值作用
includes(searchString)布尔值判断字符串是否包含指定的子串
indexOf(searchValue)索引返回子串首次出现的位置
lastIndexOf(searchValue)索引返回子串最后一次出现的位置
match(regexp)数组匹配正则表达式并返回结果
replace(searchValue, newValue)新字符串替换匹配的子字符串
3. 大小写转换
方法返回值作用
toLowerCase()小写字符串返回将所有字符转换为小写的新字符串
toUpperCase()大写字符串返回将所有字符转换为大写的新字符串
4. 切割与连接
方法返回值作用
slice(start, end)子字符串返回字符串的一个部分
split(separator)数组按照指定分隔符拆分字符串
concat(...strings)字符串连接多个字符串并返回新字符串
join(sep)字符串数组元素连接为字符串

4.2.2 Date 对象
1. 获取日期与时间
方法返回值作用
getFullYear()年份返回完整的年份(4位)
getMonth()月份返回月份(0-11)
getDate()日期返回一个月中的日期(1-31)
getDay()星期几返回星期几(0-6,0为星期天)
getHours()小时返回小时(0-23)
getMinutes()分钟返回分钟(0-59)
getSeconds()秒数返回秒数(0-59)
getMilliseconds()毫秒返回毫秒数(0-999)
2. 设置日期与时间
方法返回值作用
setFullYear(year)设置年份设置年份(4位)
setMonth(month)设置月份设置月份(0-11)
setDate(day)设置日期设置日期(1-31)
setHours(hours)设置小时设置小时(0-23)
setMinutes(minutes)设置分钟设置分钟(0-59)
setSeconds(seconds)设置秒数设置秒数(0-59)
setMilliseconds(milliseconds)设置毫秒设置毫秒(0-999)

4.2.3 Math 对象
1. 数学常用方法
方法返回值作用
Math.abs(x)数值返回 x 的绝对值
Math.ceil(x)数值返回大于或等于 x 的最小整数
Math.floor(x)数值返回小于或等于 x 的最大整数
Math.round(x)数值返回四舍五入后的值
Math.random()数值返回一个 0 到 1 之间的随机数
Math.sqrt(x)数值返回 x 的平方根
2. 极值与范围
方法返回值作用
Math.max(...values)数值返回一组数中的最大值
Math.min(...values)数值返回一组数中的最小值
Math.pow(x, y)数值返回 x 的 y 次方
Math.PI数值返回圆周率常量 π

4.2.4 JSON 对象
1. JSON 解析与字符串化
方法返回值作用
JSON.parse(text)对象/数组将 JSON 字符串解析为 JavaScript 对象
JSON.stringify(value)JSON 字符串将 JavaScript 对象转换为 JSON 字符串

4.2.5 RegExp 对象
1. 正则表达式方法
方法返回值作用
test(str)布尔值测试正则表达式是否匹配字符串
exec(str)数组返回正则表达式与字符串匹配的结果(如果有)

五、异步编程与事件机制

5.1 异步基础

5.1.1 同步 vs 异步
  • 同步(Synchronous):任务按顺序逐行执行,前一个任务不完成,后一个任务无法开始。
  • 异步(Asynchronous):某些操作可在“等待结果”的同时继续执行其他任务。

📌 示例:

console.log('A');
setTimeout(() => console.log('B'), 1000);
console.log('C');
// 输出顺序:A → C → B
5.1.2 回调函数与 Callback Hell
  • 回调函数:将一个函数作为参数传给另一个函数,用于异步任务完成后执行。
  • 回调地狱(Callback Hell):多个嵌套回调,导致代码结构混乱、难以维护。

📌 示例:

doSomething(function(result1) {doSomethingElse(result1, function(result2) {doThirdThing(result2, function(result3) {console.log('All done!');});});
});

5.2 Promise 与 async/await


5.2.1 Promise 构造与链式调用(进阶版)
  • Promise 是异步编程的核心机制,表示一个可能现在、将来或永不完成的值
  • 状态只能从 pendingfulfilledpendingrejected,不可逆。

一、创建 Promise 实例
const p = new Promise((resolve, reject) => {const data = getData();if (data) resolve(data);else reject(new Error("获取失败"));
});
  • resolve(value):表示成功,进入 .then() 分支
  • reject(error):表示失败,进入 .catch() 分支

二、链式调用(then / catch / finally)
p.then(result => {console.log("成功:", result);return result + "!";
}).then(modified => {console.log("链式处理:", modified);
}).catch(err => {console.error("捕获错误:", err);
}).finally(() => {console.log("无论成功失败都会执行");
});
  • .then() 可以返回新值传递给下一个 .then()
  • .catch() 捕获任意前面出现的错误
  • .finally() 不处理值,仅用于收尾动作(如关闭 loading)

三、错误传播机制

.then() 中抛出错误,会直接被后面的 .catch() 捕获。

p.then(() => {throw new Error("出错了");
}).catch(err => {console.log("捕获到错误", err.message);
});

四、Promise 嵌套与避免回调地狱
getUserInfo().then(user => {return getPostsByUser(user.id);
}).then(posts => {return getCommentsForPost(posts[0].id);
});
  • 通过链式结构代替回调嵌套,实现逻辑扁平化
  • 若返回的是一个新的 Promise,则自动等待其执行完成

五、常见错误使用案例(警示)
// ⚠️ 不要这样写
p.then(res => {doSomething(res, function(result) {// 回调地狱又来了});
});

应改写为:

p.then(res => doSomethingAsync(res)).then(next => console.log(next));

非常好,Promise 除了构造函数和链式调用外,还有一组非常实用的静态方法(类方法),适用于多个异步任务的管理与控制。以下是完整补充,按照清晰的结构归类呈现:


🔹 5.2.2 Promise 所有方法汇总


✅ 一、构造函数实例方法
方法作用特点
new Promise(fn)创建一个新的 Promise 实例传入 resolvereject 两个函数参数
.then(onFulfilled)注册成功回调函数支持链式调用
.catch(onRejected)注册失败回调函数.then(null, onRejected) 的语法糖
.finally(fn)无论成功/失败都会执行不影响返回值传递

✅ 二、静态方法(类方法)
1. Promise.resolve(value)
  • 返回一个状态为 fulfilled 的 Promise
  • 如果传入的是一个 Promise,会直接返回
Promise.resolve(42).then(console.log); // 42
2. Promise.reject(error)
  • 返回一个状态为 rejected 的 Promise
  • 通常用于封装异常
Promise.reject("失败").catch(console.error); // 失败

3. Promise.all([p1, p2, …])
  • 等待所有 Promise 成功,才 resolve,否则立即 reject
  • 返回值是所有结果的数组(按顺序)
Promise.all([p1, p2]).then(([r1, r2]) => {console.log(r1, r2);
});

🧠 常用于:并发请求,必须都成功


4. Promise.race([p1, p2, …])
  • 谁先完成(成功或失败),就采用谁的结果
  • 竞速场景:如加载动画 vs 请求超时
Promise.race([fetchData(),timeoutPromise(3000)
]).then(console.log).catch(console.error);

5. Promise.allSettled([p1, p2, …])
  • 等待所有 Promise 都结束(无论成功或失败)
  • 每一项返回 { status, value }{ status, reason }
Promise.allSettled([p1, p2]).then(results => {results.forEach(r => console.log(r.status));
});

🧠 常用于:统计、批处理,不能因为一个失败而中断


6. Promise.any([p1, p2, …])
  • 谁先成功就 resolve全部失败才 reject
  • ES2021 新增
Promise.any([Promise.reject("失败1"),Promise.resolve("成功"),Promise.reject("失败2")
]).then(console.log); // 输出:"成功"

🧠 常用于:只需一个成功即可,如镜像 CDN 请求


✅ 三、对比总结
方法成功策略失败策略典型应用
Promise.all全部成功任意失败立即中止并行任务且都要成功
Promise.race谁先返回谁先返回超时控制
Promise.allSettled不关心不关心全部结果分析
Promise.any任意一个成功即可全部失败才失败多镜像请求、降级处理
✨ 小贴士:手写模拟 Promise.all(核心思维训练)
function promiseAll(promises) {return new Promise((resolve, reject) => {let result = [], count = 0;promises.forEach((p, i) => {Promise.resolve(p).then(val => {result[i] = val;count++;if (count === promises.length) resolve(result);}).catch(reject);});});
}
5.2.3 async/await
  • async 声明函数返回一个 Promise。
  • await 暂停异步函数执行,等待 Promise 结果。

📌 示例:

async function fetchData() {try {const data = await getData();console.log(data);} catch (error) {console.error('Error:', error);}
}

5.3 事件循环机制(Event Loop)

5.3.1 宏任务 vs 微任务
类型示例执行时机
宏任务setTimeoutsetIntervalI/OsetImmediate(Node)每轮事件循环开始时调度
微任务Promise.thenqueueMicrotaskMutationObserver(浏览器)当前宏任务执行完立即执行所有微任务

📌 执行顺序示例:

console.log('start');setTimeout(() => console.log('setTimeout'), 0);
Promise.resolve().then(() => console.log('promise'));
queueMicrotask(() => console.log('microtask'));
console.log('end');// 输出:start → end → promise → microtask → setTimeout

5.3.2 浏览器中的事件循环流程
  1. 执行全局同步代码(主线程 → 调用栈)
  2. 执行所有微任务队列
  3. 执行一个宏任务队列中的任务
  4. 重复步骤 2 → 3,直到所有任务完成

5.3.3 Node.js 中的事件循环阶段

Node.js 的事件循环更复杂,包含 6 个阶段(基于 libuv):

阶段描述
timers执行 setTimeoutsetInterval 回调
pending callbacks执行一些系统操作的回调(如 TCP 错误)
idle/prepare内部使用
poll处理 I/O 事件,如果没有则可能进入 check 阶段或等待
check执行 setImmediate() 的回调
close callbacks执行如 socket.on('close', fn) 等关闭回调

✅ 每个阶段之间都会清空微任务队列(process.nextTick & Promise)

📌 微任务优先级:

process.nextTick > Promise.then > 宏任务(setTimeout、setImmediate)

📌 Node 示例:

setTimeout(() => console.log('timeout'), 0);
setImmediate(() => console.log('immediate'));Promise.resolve().then(() => console.log('promise'));
process.nextTick(() => console.log('nextTick'));// 输出顺序:nextTick → promise → timeout/immediate(取决于系统)

✅ 总结:执行顺序记忆口诀

  • 浏览器中:同步 → 微任务 → 宏任务
  • Node.js 中:同步 → nextTick → Promise → 各阶段宏任务

💡提示:Node.js 中的 setImmediate 可能比 setTimeout(fn, 0) 更快执行,但不保证一致顺序。


六、DOM 与 BOM 操作

6.1 DOM 基础(全面分类)


6.1.1 节点获取与遍历
方法描述返回类型
getElementById(id)根据 ID 获取节点单个元素
getElementsByClassName(class)根据类名获取类数组
getElementsByTagName(tag)根据标签名获取类数组
querySelector(selector)CSS 选择器,获取首个匹配节点单个元素
querySelectorAll(selector)CSS 选择器,获取全部匹配节点NodeList(类数组)
parentNode / childNodes / nextSiblingDOM 树节点关系遍历节点对象

6.1.2 节点创建、插入、删除、克隆
操作方法示例
创建元素createElement(tag)let div = document.createElement('div')
插入appendChild()append()insertBefore()parent.appendChild(child)
删除removeChild()remove()parent.removeChild(el)
替换replaceChild(newEl, oldEl)替换节点
克隆cloneNode(true)复制节点

6.1.3 节点内容与属性操作
操作方法 / 属性示例
获取/设置文本innerText / textContentel.textContent = 'Hello'
获取/设置 HTMLinnerHTMLel.innerHTML = '<b>Hi</b>'
获取/设置属性getAttribute() / setAttribute()el.setAttribute('href', '#')
移除属性removeAttribute()el.removeAttribute('title')
操作类名classList.add/remove/toggle/containsel.classList.toggle('show')
操作样式style.propertyel.style.color = 'red'

6.1.4 元素位置与尺寸获取
属性 / 方法描述示例
offsetTop / offsetLeft元素相对 offsetParent 的偏移el.offsetTop
offsetWidth / offsetHeight包含 padding 和 borderel.offsetHeight
clientWidth / clientHeight包含 padding 不含 borderel.clientWidth
scrollTop / scrollLeft滚动距离el.scrollTop
getBoundingClientRect()获取元素相对视口的位置与尺寸el.getBoundingClientRect()

6.1.5 常用事件分类
📌 一)鼠标事件
事件名说明
click / dblclick点击 / 双击
mousedown / mouseup按下 / 弹起
mousemove鼠标移动
mouseenter / mouseleave进入 / 离开元素(不冒泡)
mouseover / mouseout进入 / 离开(冒泡)
contextmenu右键菜单
📌 二)键盘事件
事件名说明
keydown键盘按下
keyup键盘松开
keypress输入字符(已废弃)
📌 三)表单事件
事件名说明
submit表单提交
change表单值变化(如 select)
input输入变化(推荐用于 text 输入)
focus / blur聚焦 / 失焦
📌 四)窗口事件
事件名说明
load页面加载完成
resize窗口尺寸变化
scroll页面或元素滚动
beforeunload页面关闭前

6.1.6 事件监听与代理
操作示例
绑定事件el.addEventListener('click', fn)
移除事件el.removeEventListener('click', fn)
阻止默认行为event.preventDefault()
阻止冒泡event.stopPropagation()
事件代理绑定父级,判断 e.target
list.addEventListener('click', e => {if (e.target.tagName === 'LI') {console.log('点击了第', e.target.innerText);}
});

6.1.7 拖拽与监听移动
功能方法
拖拽事件dragstart / dragover / drop
鼠标监听移动结合 mousedownmousemovemouseup 实现

示例伪代码实现拖动:

let isDragging = false;
el.onmousedown = () => isDragging = true;
document.onmousemove = (e) => {if (isDragging) el.style.left = e.clientX + 'px';
};
document.onmouseup = () => isDragging = false;

6.2 事件模型(浏览器)

6.2.1 事件传播机制:捕获 & 冒泡

事件传播分为 三个阶段

阶段顺序阶段名称描述
捕获阶段(Capture Phase)window 自顶向下,沿着 DOM 树传递到目标元素
目标阶段(Target Phase)实际目标元素上触发的事件
冒泡阶段(Bubble Phase)从目标元素沿 DOM 树向上传递回 window

📌 示例:

element.addEventListener('click', handler, true); // 第三个参数 true 表示捕获阶段监听
element.addEventListener('click', handler, false); // false 表示冒泡阶段监听(默认)

6.2.2 阻止事件传播
方法作用
event.stopPropagation()阻止事件继续冒泡或捕获
event.stopImmediatePropagation()阻止同一元素上后续所有事件监听器执行
event.preventDefault()阻止默认行为(如表单提交、a 链接跳转)

6.2.3 自定义事件(CustomEvent)

用于手动触发和传递自定义数据的事件。

1️⃣ 创建并触发事件:
const event = new CustomEvent('myEvent', {detail: { name: 'ChatGPT', level: 99 }
});
element.dispatchEvent(event);
2️⃣ 监听事件:
element.addEventListener('myEvent', function(e) {console.log(e.detail.name); // 输出:ChatGPT
});

6.2.4 事件对象 Event

当事件触发时,监听函数会自动接收一个事件对象:

属性/方法描述
event.target实际触发事件的元素
event.currentTarget当前绑定事件的元素
event.type事件类型(如 click)
event.timeStamp触发事件的时间戳
event.defaultPrevented是否已调用 preventDefault()
event.bubbles该事件是否支持冒泡
event.cancelable是否可以取消默认操作

6.2.5 补充:事件委托(推荐实践)

通过把事件绑定在父节点上,提高性能和可维护性。

ul.addEventListener('click', function(e) {if (e.target.tagName === 'LI') {console.log('点击了:', e.target.innerText);}
});

✅ 好处:

  • 减少事件监听数量
  • 支持动态添加子元素的事件响应
6.2.6 事件绑定优先级顺序

在浏览器中,当同一元素绑定了多种事件方式,它们的触发顺序如下:

✅ 优先级顺序(由高到低):
  1. 内联绑定(HTML 属性):如 <button onclick="alert(1)">
  2. DOM0 绑定(传统方式):如 element.onclick = fn
  3. DOM2 绑定(推荐方式):如 element.addEventListener('click', fn)
⚠️ 示例说明:
<button id="btn" onclick="console.log('inline')">点击</button>
const btn = document.getElementById('btn');
btn.onclick = () => console.log('DOM0');
btn.addEventListener('click', () => console.log('DOM2'));

输出顺序:

inline
DOM0
DOM2
6.2.7 DOM 0 / DOM 2 级事件模型差异
比较项DOM 0 级事件(传统)DOM 2 级事件(标准)
绑定方式element.onclick = fnaddEventListener('click', fn, useCapture)
是否支持多个监听器❌ 只能绑定一个✅ 可绑定多个
是否支持捕获阶段❌ 不支持✅ 支持(通过第三个参数)
是否兼容 IE 低版本IE9+
是否标准推荐✅ W3C 推荐标准方式
6.2.8 React 合成事件机制(SyntheticEvent)

React 并不直接绑定原生事件,而是通过自己的事件系统(合成事件)实现更高效的管理。

📌 特点:
特性描述
合成封装对原生事件进行封装,统一不同浏览器差异
自动绑定自动使用事件委托,绑定在根节点(提高性能)
统一池化使用事件池提升性能(v17 前),需注意事件异步访问
命名风格使用驼峰命名:如 onClickonChange
✅ 示例:
<button onClick={handleClick}>点击</button>function handleClick(e) {console.log(e.nativeEvent); // 原生事件console.log(e);             // 合成事件
}
⚠️ 注意事项:
  • 异步中访问事件属性需要调用 e.persist()(在 React17 以前)
  • React 17+ 不再使用事件池,不再需要 e.persist()

6.3 BOM 操作

6.3.1 window 对象
  • 浏览器的全局对象,所有全局变量和函数都是其属性或方法。
  • 也是 BOM 的顶层对象。
常见属性/方法:
属性/方法作用
window.innerWidth / innerHeight获取窗口内容区域的宽/高(不含滚动条)
window.open(url)打开新窗口或标签页
window.alert() / confirm() / prompt()浏览器弹窗
window.scrollTo(x, y)滚动到指定位置

6.3.2 location 对象
  • 用于获取或修改当前页面的 URL。
属性/方法说明
location.href当前完整 URL,可读取或赋值跳转
location.protocol协议,如 https:
location.host / hostname / port主机、主机名、端口号
location.pathname路径部分
location.search查询字符串(如 ?id=1
location.reload()重新加载页面
location.assign(url)跳转到新 URL(有历史记录)
location.replace(url)替换当前页面(无历史记录)

6.3.3 navigator 对象
  • 描述用户浏览器的信息。
属性说明
navigator.userAgent浏览器/设备详细信息
navigator.platform操作系统平台(如 Win32)
navigator.language当前浏览器语言
navigator.onLine当前是否联网(布尔值)

6.3.4 history 对象
  • 用于操作浏览器历史记录。
方法说明
history.back()返回上一页(等同于点击后退)
history.forward()前进一页
history.go(n)前进或后退 n
history.pushState(state, title, url)添加历史记录(不会刷新页面)
history.replaceState(...)替换当前历史记录

注意:pushStatereplaceState 是 HTML5 的新特性,常用于 SPA 前端路由。


6.3.5 定时器:setTimeoutsetInterval
方法作用返回值
setTimeout(fn, delay)延迟执行一次返回定时器 ID
setInterval(fn, delay)每隔一段时间重复执行返回定时器 ID
clearTimeout(id)取消 setTimeout
clearInterval(id)取消 setInterval
示例:
const id = setTimeout(() => console.log("一次性延迟"), 1000);
clearTimeout(id);const loopId = setInterval(() => console.log("每秒执行"), 1000);
clearInterval(loopId);

⚠️ 注意内存泄漏风险:组件销毁/页面离开应清理定时器。

好的,以下是对 6.3 BOM 操作 的进一步补充,涵盖浏览器窗口通信、全局错误处理,以及实用 Web API 技巧,帮助你建立更加系统的 JavaScript 浏览器编程知识体系。

6.3.6 浏览器窗口通信:postMessage
✅ 场景:
  • 不同窗口/iframe 之间传递数据(甚至跨域);
  • 通常用于父页面与子页面之间的数据通信。
💡 基本语法:
// 发送方(通常是父窗口或 iframe)
otherWindow.postMessage(message, targetOrigin);// 接收方
window.addEventListener("message", function(event) {// event.data 是传递过来的数据// event.origin 是消息来源的域名
}, false);
✅ 参数说明:
参数说明
message发送的数据(可以是对象)
targetOrigin接收方的 origin(例如:"https://example.com")用于安全校验-w41hk4oxqyc3z0h1aq79f/)
📌 示例:
// 子页面向父页面发送消息
window.parent.postMessage({ type: "resize", height: 600 }, "https://yourdomain.com");// 父页面接收子页面消息
window.addEventListener("message", (event) => {if (event.origin !== "https://yourdomain.com") return; // 安全校验console.log("子页面消息:", event.data);
});
6.3.7 全局错误处理机制
window.onerror

用于捕获运行时错误,防止页面崩溃时无反馈。

window.onerror = function (message, source, lineno, colno, error) {console.error("捕获错误:", message, "位置:", source, lineno, colno);// 可上传日志服务器return true; // 阻止默认报错行为
};
window.addEventListener('error')

更强大,可以捕获资源加载错误(如图片、脚本加载失败):

window.addEventListener("error", function (e) {if (e.target instanceof HTMLImageElement) {console.warn("图片加载失败:", e.target.src);}
}, true); // 第三个参数设为 true 才能捕获资源加载错误
window.addEventListener('unhandledrejection')

用于捕获未被 .catch() 捕获的 Promise 错误:

window.addEventListener("unhandledrejection", (event) => {console.error("未处理的 Promise 错误:", event.reason);
});
6.3.8 Web API 实用技巧
✅ 剪贴板 API
// 复制文本到剪贴板
navigator.clipboard.writeText("复制的内容").then(() => alert("已复制")).catch(err => console.error("复制失败", err));// 读取剪贴板内容(需 HTTPS 环境+用户触发)
navigator.clipboard.readText().then(text => console.log("读取到剪贴板内容:", text));

⚠️ 注意安全性:大多浏览器要求用户手势触发(如点击)

✅ 页面可见性 API(Page Visibility)

判断页面是否处于活跃(当前标签页是否可见),适合用于:

  • 暂停动画、视频播放;
  • 控制数据轮询行为等。
document.addEventListener("visibilitychange", () => {if (document.visibilityState === "hidden") {console.log("页面不可见,暂停轮询");} else {console.log("页面可见,恢复轮询");}
});
✅ 屏幕尺寸与滚动监听
// 获取滚动位置
window.scrollY; // 垂直滚动距离
window.scrollX; // 水平滚动距离// 监听页面滚动
window.addEventListener("scroll", () => {console.log("滚动中...", window.scrollY);
});

七、模块化与工具链

7.1 模块化发展历程

模块化是前端工程化的核心。它的演化反映了前端开发复杂度的提升和工具生态的进化。


7.1.1 IIFE(立即执行函数表达式)

最原始的模块化方式,用闭包封装变量避免污染全局作用域。

(function () {var name = "模块内部变量";console.log(name);
})();
  • ✅ 优点:避免全局变量污染
  • ❌ 缺点:无模块复用能力、缺乏依赖管理

7.1.2 CommonJS(Node.js 中使用)
// a.js
module.exports = {sayHi: () => console.log("Hi"),
};// b.js
const a = require("./a.js");
a.sayHi();
  • ✅ 特点:同步加载,适用于服务器端
  • ❌ 浏览器不支持,需要打包工具(如 Webpack)转换

7.1.3 AMD(Asynchronous Module Definition)

浏览器端模块化规范,代表库:RequireJS

define(["moduleA"], function (moduleA) {moduleA.doSomething();
});
  • ✅ 特点:异步加载,适合浏览器
  • ❌ 缺点:语法繁琐、可读性差

7.1.4 UMD(Universal Module Definition)

兼容 CommonJS、AMD 和浏览器全局变量

(function (root, factory) {if (typeof define === "function" && define.amd) {define([], factory);} else if (typeof exports === "object") {module.exports = factory();} else {root.myModule = factory();}
})(this, function () {return {};
});

7.1.5 ES6 模块化(现代主流)
// module.js
export const name = "JS模块";
export default function greet() {console.log("Hello ES Module");
}// main.js
import greet, { name } from "./module.js";
greet();
  • ✅ 静态加载、编译时可分析依赖
  • ✅ 浏览器原生支持(需 type=“module”)
  • ✅ 与打包工具完美结合

7.2 前端开发工具链概览

从代码撰写 → 转译兼容 → 打包构建 → 代码规范 → 性能优化,全流程涉及以下关键工具:


7.2.1 构建与打包工具
工具主要用途特点
Webpack模块打包器配置灵活、插件强大、学习曲线略高
Vite新一代构建工具极速启动、基于原生 ESM、现代开发优选
Rollup打包库的首选工具构建体积小,Tree-shaking 效果好

7.2.2 代码转译与语法支持
工具作用
Babel将 ES6+ 代码转为向后兼容的 JavaScript
TypeScript增加类型系统、增强开发体验

7.2.3 代码质量与风格规范
工具用途
ESLint静态代码检查,防止潜在错误
Prettier统一代码格式,提升团队协作效率

✅ 推荐配合 IDE 插件 + Git Hooks 实现自动检查 + 修复


7.2.4 常见工具集成方式
  • 项目初始化:npm init vite@latest / create-react-app
  • 构建命令:npm run build
  • 开发模式:npm run dev(通常开启热更新)
  • 检查格式:eslint src/prettier --write .

🔧 补充建议

✅ 强烈建议配合 husky + lint-staged 实现提交前校验:

npx husky-init && npm install
npx husky add .husky/pre-commit "npx lint-staged"

八、ES6+ 新特性

ES6 是 ECMAScript 的重大升级版本,后续 ES7+ 持续增强语法和内置能力,使 JavaScript 更现代、更强大。以下按功能模块系统归纳。


8.1 语法增强与数据结构

8.1.1 解构赋值

快速提取对象或数组中的值

const { name, age } = person;
const [a, b] = [1, 2];
  • ✅ 默认值、嵌套解构
  • ✅ 可用于函数参数

8.1.2 模板字符串

多行字符串 & 插值表达式

const msg = `Hello, ${user.name}!`;

8.1.3 扩展与收集运算符(...
  • 展开:将数组/对象拆开

    const arr2 = [...arr1];
    const obj2 = { ...obj1 };
    
  • 收集:函数剩余参数

    function fn(...args) {}
    

8.1.4 Symbol(独一无二的值)

创建唯一键,适合定义私有属性

const sym = Symbol('key');
obj[sym] = 'value';

8.1.5 Set & Map(全新数据结构)
特性SetMap
存储值的集合键值对
是否重复否(键唯一)
常用方法add, has, deleteset, get, has, delete
const s = new Set([1, 2, 2]); // 去重
const m = new Map([["a", 1]]);

8.1.6 可迭代对象与 for…of

可使用 for...of...展开符 的对象:Array、Map、Set、字符串等

for (const item of set) {}

8.2 Class 与模块系统

8.2.1 class 类定义与继承
class Person {constructor(name) {this.name = name;}greet() {console.log(`Hi, ${this.name}`);}
}
  • extends 实现继承
  • super() 调用父类构造器
  • ✅ 私有属性:#privateName

8.2.2 模块系统(import / export
// 导出
export const name = "Tom";
export default function greet() {}// 导入
import greet, { name } from "./module.js";
  • 支持:默认导出 / 命名导出 / 重命名 / 整体导入

8.3 常用内置 API 与语法糖

8.3.1 新增 API
方法作用
Object.entries(obj)返回键值对数组
Object.values(obj)返回值数组
Array.flat(depth)扁平化嵌套数组
Array.includes(val)判断是否包含
Promise.allSettled()所有 Promise 返回后统一处理,无论成功失败

8.3.2 Nullish Coalescing(??

只有 nullundefined 才触发右侧默认值

const val = input ?? "默认值";
  • ❌ 不会因 ''0 而触发

8.3.3 Optional Chaining(?.

安全读取深层属性,避免报错

const city = user?.address?.city;

🔍 记忆建议:

  • ✅ 解构 & 展开:多写函数参数和对象操作
  • ✅ Symbol:对象私有成员
  • ✅ Set/Map:处理去重与映射优于 Object
  • ✅ ?? 与 ?.:null 安全写法,高频出现于项目中

九、浏览器通信与网络

现代前端开发离不开浏览器与服务器之间的高效通信,本章将系统梳理 AJAX、跨域机制、本地存储方案与 Web 通信能力。


9.1 浏览器请求方式

9.1.1 XMLHttpRequest 基础(XHR)
  • 原始的 AJAX 技术核心
  • 支持事件监听与状态码处理
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/data');
xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {console.log(xhr.responseText);}
};
xhr.send();

9.1.2 Fetch API

更现代的异步请求方式,基于 Promise

fetch('/api/data').then(res => res.json()).then(data => console.log(data)).catch(err => console.error(err));
  • ✅ 更简洁
  • ✅ 默认不携带 cookie(需配置)
  • ✅ 不会自动 reject 4xx/5xx(需手动判断 res.ok

9.1.3 封装 Fetch 常用方法
async function request(url, options = {}) {const res = await fetch(url, options);if (!res.ok) throw new Error('网络错误');return res.json();
}

9.2 跨域处理策略

9.2.1 同源策略

协议 + 域名 + 端口号 三者相同才算同源
不同源会受到限制(如 DOM 操作、AJAX 请求)


9.2.2 解决方式对比
方法原理优缺点
CORS设置响应头 Access-Control-Allow-Origin推荐,标准方案
JSONP利用 <script> 标签不受同源限制仅支持 GET,请求安全性差
代理转发本地服务器转发请求,绕过浏览器限制需后端支持,常见于开发环境
PostMessage窗口间通信(iframe 或新窗口)跨域数据安全通信

9.3 本地存储方式对比

9.3.1 Cookie
  • 每次请求自动携带,常用于身份验证
  • 有大小限制(~4KB)
  • 支持设置过期时间、路径、域
document.cookie = "token=123;path=/;max-age=3600";

9.3.2 localStorage
  • 永久存储(直到手动清除)
  • 单域名下最大约 5MB
  • 仅支持字符串
localStorage.setItem("key", "value");
localStorage.getItem("key");

9.3.3 sessionStorage
  • 页面会话级别,标签页关闭即清除
  • API 与 localStorage 相同

✅ 对比总结:
特性CookielocalStoragesessionStorage
是否随请求发送
生命周期可设置永久会话
大小限制4KB5MB+5MB+
跨标签页共享

9.4 实用通信机制补充

9.4.1 浏览器窗口通信:postMessage

用于主窗口与 iframe / 子窗口 / 弹窗间安全通信

window.postMessage("数据", "https://other.com");window.addEventListener("message", (event) => {console.log(event.origin, event.data);
});

9.4.2 全局错误监听
  • 捕获 JS 报错信息,便于上报与监控
window.onerror = function (msg, url, line, col, error) {console.error('捕获错误:', msg, error);
};window.addEventListener('error', (event) => {console.log('资源加载错误:', event.target);
});

9.4.3 实用 Web API 技巧
API功能示例
navigator.clipboard.writeText()写入剪贴板复制文本
document.visibilityState页面可见性检测visibilitychange 监听
navigator.onLine网络状态检测离线/在线判断
Performance API页面性能分析performance.now()

好的,下面是第九章:浏览器通信与网络的进一步补充,涵盖更深入的网络通信机制及相关 API,包括 WebSocket、服务端事件(SSE)、网络状态检测、离线缓存等内容。


9.5 实时通信技术

9.5.1 WebSocket 长连接

一种在单个 TCP 连接上进行全双工通信的协议,适合实时聊天、推送通知等场景。

使用示例:

const socket = new WebSocket('wss://example.com/socket');socket.onopen = () => {socket.send('Hello Server!');
};socket.onmessage = (event) => {console.log('收到消息:', event.data);
};socket.onerror = (err) => console.error('连接错误:', err);
socket.onclose = () => console.log('连接关闭');
  • ✅ 持久连接,适合高频交互
  • ❌ 需服务端配套支持,维护成本高

9.5.2 Server-Sent Events(SSE)

浏览器从服务端接收单向推送数据(基于 HTTP)

const source = new EventSource('/api/events');source.onmessage = function (event) {console.log('服务端推送:', event.data);
};
  • ✅ 简洁、自动重连、支持事件命名
  • ❌ 只支持单向、部分浏览器支持

9.6 网络状态与页面生命周期

9.6.1 网络状态检测
console.log(navigator.onLine); // true or falsewindow.addEventListener('online', () => console.log('网络恢复'));
window.addEventListener('offline', () => console.log('网络断开'));

9.6.2 页面可见性检测
document.addEventListener('visibilitychange', () => {if (document.visibilityState === 'hidden') {console.log('页面隐藏');} else {console.log('页面可见');}
});
  • 可用于暂停动画、视频、轮询请求

9.7 离线缓存与存储技术

9.7.1 Cache API(Service Worker)

配合 Service Worker 实现离线缓存、离线访问页面内容

caches.open('v1').then(cache => {cache.addAll(['/index.html', '/styles.css']);
});
  • 与 fetch 结合,可拦截请求并返回缓存
  • 需 HTTPS 环境下注册 Service Worker

9.7.2 IndexedDB

浏览器提供的事务型数据库,可存储结构化数据

const request = indexedDB.open('myDB', 1);
request.onsuccess = (event) => {const db = event.target.result;console.log('数据库打开成功');
};
  • 支持索引、事务、高容量数据
  • 常用于大型离线 Web 应用(PWA)

9.8 网络调优与安全

9.8.1 请求优化技巧
  • 开启 Keep-Alive 复用连接
  • 使用 CDN 缓存静态资源
  • 图片懒加载 + 资源压缩
  • 合理使用缓存头部(Cache-Control、ETag)

9.8.2 网络安全机制
  • HTTPS 加密传输
  • 防 XSS/CSRF 攻击
  • 输入校验与输出转义
  • 设置 Content-Security-Policy 安全策略头

十、性能优化与安全

10.1 性能优化

10.1.1 资源懒加载

将不在视口内的资源延迟加载,减少初始加载时间。

  • 图片懒加载:
<img data-src="image.jpg" class="lazyload" alt="Lazy Load Image">
  • JavaScript 懒加载:
const script = document.createElement('script');
script.src = 'path/to/your/script.js';
document.body.appendChild(script);
  • 适用场景: 图片、视频、JavaScript 等
10.1.2 事件节流与防抖

节流 (Throttling)防抖 (Debouncing) 用于控制频繁触发的事件,如滚动、输入等。

  • 防抖:
function debounce(fn, delay) {let timer;return function (...args) {clearTimeout(timer);timer = setTimeout(() => fn(...args), delay);};
}
  • 节流:
function throttle(fn, delay) {let last = 0;return function (...args) {const now = Date.now();if (now - last >= delay) {last = now;fn(...args);}};
}
10.1.3 DOM 优化
  • 减少 DOM 操作: 批量更新、避免频繁重排与重绘(例如使用 DocumentFragment
  • 缓存查询结果: 存储对 DOM 的查询结果,避免重复查找
const button = document.getElementById('myButton');
// 使用变量缓存 DOM 查找
10.1.4 异步加载与延迟加载
  • 异步加载: 使用 asyncdefer 属性来异步加载 JavaScript 文件,避免阻塞渲染。
<script src="script.js" async></script>
<script src="script.js" defer></script>
  • 分块加载: 使用 Webpack 等工具进行代码分块,按需加载,提升初次加载速度。
10.1.5 缓存策略

缓存能够显著提高性能,减少重复的网络请求。

  • Service Worker + Cache API: 在浏览器端缓存资源,离线访问。
  • HTTP 缓存: 使用 Cache-ControlETag 头部进行缓存控制。
// 在 Service Worker 中缓存请求资源
caches.open('v1').then((cache) => {cache.add('/index.html');
});
  • LocalStorage / IndexedDB: 在本地存储应用数据,避免频繁请求数据。
10.1.6 图片与视频优化
  • 图片格式优化: 使用现代格式(如 WebP)来减少图片大小。
  • SVG 图标替代位图图标:SVG 比 PNG/JPG 更加灵活且文件更小。
  • 懒加载: 只在用户滚动到页面时才加载图片。

10.2 前端安全

10.2.1 XSS(跨站脚本攻击)

攻击者通过注入恶意脚本,窃取用户数据或篡改网页内容。

  • 防御方法:
    • 输入验证与输出编码: 对用户输入进行严格的验证和转义,避免脚本执行。
    • 使用 CSP(内容安全策略) 来限制加载的脚本源。
<meta http-equiv="Content-Security-Policy" content="script-src 'self'">
  • 避免内联脚本: 使用外部脚本文件,禁止内联 JavaScript 代码。
10.2.2 CSRF(跨站请求伪造)

攻击者伪造用户请求,造成未授权操作。

  • 防御方法:
    • Token 验证: 每次提交请求时,附加一个唯一的 CSRF Token(在表单或请求头中传递),服务器验证是否匹配。
    • SameSite Cookies: 使用 SameSite 属性,限制 Cookie 在跨站请求时是否随请求一起发送。
document.cookie = "token=your_token; SameSite=Strict;";
10.2.3 Clickjacking(点击劫持)

攻击者通过透明 iframe 诱使用户点击其并非意图点击的内容。

  • 防御方法:
    • 使用 X-Frame-Options 头部阻止页面被嵌套在 iframe 中。
<meta http-equiv="X-Frame-Options" content="DENY">
10.2.4 内容安全策略(CSP)

CSP 是一种防止 XSS 攻击的安全机制,限制浏览器加载资源的源。

  • 基本 CSP 配置:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline';">
  • 策略设计:
    • default-src:指定默认的加载源
    • script-src:限制脚本的来源
    • style-src:限制样式的来源
10.2.5 其他前端安全防护
  • HTTPOnly Cookie: 防止 JavaScript 访问 Cookie,增强安全性。
  • HSTS(HTTP 严格传输安全): 强制浏览器与服务器之间使用 HTTPS 通信。
// 在服务器上启用 HSTS
Strict-Transport-Security: max-age=31536000; includeSubDomains
  • 两步验证: 通过发送验证码或短信来加强用户的身份验证。

十一、项目实战与面试要点

11.1 项目实践

  • Todo List、画板、购物车、小型 SPA 实现
  • 调试技巧与错误捕获(Try/Catch、window.onerror)

11.2 面试高频题

  • 手写 Promise、深拷贝、节流/防抖
  • 输出题、闭包题、原型继承题

十二、进阶方向推荐

  • TypeScript 基础与应用
  • React / Vue / Svelte 框架精通
  • 前端架构、微前端、性能监控
  • WebAssembly、Serverless、PWA

相关文章:

  • 【数据结构】栈
  • 【MyBatis-8】MyBatis对象关联查询详解:高效处理复杂关系映射
  • Altium Designer AD如何输出PIN带网络名的PDF装配图
  • 内存中的“BANK”
  • 深入理解Python逻辑判断、循环与推导式(附实战案例)
  • Shell脚本与Xshell的使用、知识点、区别及原理
  • 演员评论家算法
  • 缺乏需求变更的影响评估,如何降低项目风险
  • Linux操作系统之进程(一):进程属性与进程创建
  • 交流充电桩IEC 61851-1和IEC 61851-21-2标准测试项目
  • MySQL推荐书单:从入门到精通
  • gradle--问答
  • 在 STM32 上使用 register 关键字
  • 如何访问云相关的api
  • python数据分析常用的10个核心库
  • 题海拾贝:P1833 樱花
  • vue3项目创建-配置-elementPlus导入-路由自动导入
  • 滑动窗口——水果成篮
  • Java后端快速生成验证码
  • 【NextPilot日志移植】params.c解析
  • 上海国际电影节纪录片单元,还世界真实色彩
  • 云南一男子持刀致邻居3死1重伤案二审开庭,未当庭宣判
  • 李公明 | 一周画记:印巴交火会否升级为第四次印巴战争?
  • 在地球另一端的交流,架起2万公里间更多共赢的桥梁
  • 人民空军:网上出现的“运-20向外方运送物资”为不实消息
  • 法院就“行人相撞案”道歉:执法公正,普法莫拉开“距离”