Web前端考核 JavaScript知识点详解

news2025/3/28 7:31:17

一、JavaScript 基础语法

1.1 变量声明

关键字作用域提升重复声明暂时性死区
var函数级
let块级
const块级
1.1.1变量提升的例子

在 JavaScript 中,var 声明的变量会存在变量提升的现象,而 letconst 则不会。变量提升是指变量的声明会被提升到当前作用域的顶部,但赋值操作不会提升。

1. var 的变量提升
onsole.log(a); // 输出:undefined
var a = 10;
console.log(a); // 输出:10

//重复声明特性
var b;
var b;
onsole.log(b); // 输出:undefined
var b = 10;
console.log(b); // 输出:10

解释

  • 虽然 var a = 10; 是在 console.log(a); 之后声明的,但由于变量提升,var a 的声明会被提升到作用域的顶部。类似于var a;但是不进行赋值操作。
  • 因此,第一次 console.log(a); 不会报错,而是输出 undefined(因为赋值操作 a = 10 没有被提升)。
  • 第二次 console.log(a); 输出 10,因为此时已经完成了赋值。
2. letconst 的暂时性死区
console.log(b); // 报错:ReferenceError: Cannot access 'b' before initialization
let b = 20;
console.log(b); // 输出:20
console.log(c); // 报错:ReferenceError: Cannot access 'c' before initialization
const c = 30;
console.log(c); // 输出:30

解释

  • letconst 声明的变量不会提升,且在声明之前访问会触发“暂时性死区”(Temporal Dead Zone, TDZ),导致报错。
  • 只有在声明之后,才能正常访问 letconst 声明的变量。

1.1.2 变量提升的代码运行过程
1.var 的代码运行过程
// 实际运行过程
var a; // 声明被提升到作用域顶部
console.log(a); // 输出:undefined
a = 10; // 赋值操作
console.log(a); // 输出:10
2.letconst 的代码运行过程
// 实际运行过程
console.log(b); // 报错:ReferenceError
let b = 20; // 声明和赋值
console.log(b); // 输出:20

// 若我们在上面自己声明好b,则也是报undefined。
let b
console.log(b); // 报错:undefined
b = 20; // 声明和赋值
console.log(b); // 输出:20

//注意我们不能直接const b;这样子会报错的。const 在声明时必须立即初始化(即赋值),否则会报错。这是 const 的一个重要特性,也是它与 let 和 var 的主要区别之一。

1.1.3变量提升的总结
特性varletconst
作用域函数作用域块级作用域块级作用域
变量提升✅ 声明提升,值为 undefined❌ 存在暂时性死区❌ 存在暂时性死区
重复声明✅ 允许重复声明❌ 不允许重复声明❌ 不允许重复声明
修改值✅ 可以重新赋值✅ 可以重新赋值❌ 不能重新赋值(常量)

1.2 数据类型

基本类型

  • Number
  • String
  • Boolean
  • Undefined
  • Null
  • Symbol
  • BigInt

引用类型

  • Object
  • Array
  • Function
/*
typeof 是一个一元操作符,用于检测一个值的基本数据类型。它返回一个表示数据类型的字符串
*/
// 类型检测
console.log(typeof 42); // "number"
console.log(typeof "hello"); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (历史遗留问题)
console.log(typeof []); // "object"
console.log(typeof {}); // "object"
console.log(typeof function() {}); // "function"
console.log(typeof Symbol("id")); // "symbol"
console.log(typeof 123); // "bigint"
/*
instanceof 是一个二元操作符,用于检测一个对象是否是某个构造函数的实例。它可以用来检测对象的继承关系。
*/
console.log([] instanceof Array); // true
console.log({} instanceof Object); // true
console.log(function() {} instanceof Function); // true

class Animal {}
class Dog extends Animal {}
const dog = new Dog();
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true (继承关系)
console.log(dog instanceof Object); // true (所有对象都是 Object 的实例)

  • typeof null 返回 "object",这是 JavaScript 的一个历史遗留问题。
  • typeof 无法区分数组和普通对象,它们都返回 "object"
  • instanceof 返回一个布尔值:
    • true:对象是构造函数的实例。
    • false:对象不是构造函数的实例。

在这里我突然想知道symbol和bigint是什么东西?因为好像都没怎么用过,所以我上网搜了一下,总结了以下大概:

1.1 什么是 Symbol

  • Symbol 是一种原始数据类型,类似于 numberstringboolean 等。
  • 每个 Symbol 值都是唯一的,即使它们的描述相同。
  • Symbol 值通常用作对象的属性名,以确保属性名不会冲突。

1.2 创建 Symbol

使用 Symbol() 函数可以创建一个 Symbol 值。可以传递一个可选的描述字符串,用于调试和区分不同的 Symbol

const sym1 = Symbol();
const sym2 = Symbol("description"); // 带描述的 Symbol
const sym3 = Symbol("description");

console.log(sym1); // Symbol()
console.log(sym2); // Symbol(description)
console.log(sym2 === sym3); // false,即使描述相同,Symbol 也是唯一的

1.3. Symbol 的特性

1.4 唯一性

每个 Symbol 值都是唯一的,即使它们的描述相同。可能大家听不懂,直接上代码。

const sym1 = Symbol("id");
const sym2 = Symbol("id");

console.log(sym1 === sym2); // false
1.5 不可变性
const sym = Symbol("id");
sym.description = "new description"; // 无效
console.log(sym.description); // "id"
2.3 不可枚举性

Symbol 属性不会出现在 for...inObject.keys() 的遍历中。

const obj = {
  [Symbol("id")]: 123,
  name: "Alice"
};

console.log(Object.keys(obj)); // ["name"]
for (let key in obj) {
  console.log(key); // 只输出 "name"
}

说到这里,还是要回归我们为什么要用symbol?

2.1 避免属性名冲突

Symbol 可以用作对象的属性名,确保属性名不会与其他属性冲突。

const id = Symbol("id");
const user = {
  name: "Alice",
  [id]: 123 ,// 使用 Symbol 作为属性名
  id:1
};
//语法要求:当使用Symbol作为属性名时,必须将其包裹在方括号[]中。这是因为方括号允许使用变量或表达式作为属性名,而Symbol变量属于这种情况。
console.log(user[id]); // 123
console.log(user.id); // 1
2.2 定义对象的私有属性

由于 Symbol 属性不会被常规方法遍历到,可以用来模拟私有属性。

const age = Symbol("age");
const person = {
  name: "Bob",
  [age]: 30
};

console.log(person[age]); // 30
console.log(Object.keys(person)); // ["name"]

BigInt 是 JavaScript 中的一种新的基本数据类型(ES2020 引入),专门用来表示超大整数,解决传统 Number 类型无法精确处理大整数的问题。


3.1BigInt 的核心特点

  1. 表示超大整数

    • Number 类型能精确表示的最大整数是 2^53 - 1(即 9007199254740991),超过这个值会丢失精度。
    • BigInt 可以表示任意大的整数(理论上仅受内存限制)。
    const maxNumber = 9007199254740991; // Number 的最大安全整数
    const bigIntNum = 9007199254740992n; // BigInt 表示更大的整数
    console.log(maxNumber + 1); // 9007199254740992 ✅
    console.log(maxNumber + 2); // 9007199254740992 ❌ 精度丢失!
    console.log(bigIntNum + 1n); // 9007199254740993n ✅
    
  2. 语法
    • 在数字末尾加 n(例如 123n)。
    • 或通过 BigInt() 函数转换(例如 BigInt(123))。
  3. 运算限制
    • 不能直接与 Number 混合运算,必须统一类型:

      console.log(1n + 2); // 报错:Cannot mix BigInt and other types
      console.log(1n + 2n); // 3n ✅
      
    • 比较运算符(如 ==、>)可以直接使用:

      console.log(1n < 2); // true ✅
      
  4. 用途

    • 处理金融、加密算法中的超大整数。
    • 数据库中的大 ID(如 Twitter 的推文 ID)。
    • 数学计算(如大数阶乘、质数验证)。

注意事项
  • JSON 不支持JSON.stringify() 会忽略 BigInt 属性,需要手动处理序列化。
  • 兼容性:现代浏览器和 Node.js 支持,但旧环境需检查兼容性。
  • 性能BigInt 运算比 Number 稍慢,但可忽略不计。

示例
// 定义 BigInt
const big1 = 123456789012345678901234567890n;
const big2 = BigInt("987654321098765432109876543210");

// 运算
const sum = big1 + big2; // 1111111110111111111011111111100n
const isEven = big1 % 2n === 0n; // 判断是否为偶数

// 转换
console.log(big1.toString()); // "123456789012345678901234567890"
console.log(Number(big1)); // 1.2345678901234568e+29(可能丢失精度!)

好啦,扩展了这两个属性,下面继续我们的其他方面的学习~~

1.3 JavaScript 运算符详解

1. 算术运算符

let a = 10, b = 3;

console.log(a + b);  // 13 ➕
console.log(a - b);  // 7 ➖
console.log(a * b);  // 30 ✖️
console.log(a / b);  // 3.333... ➗
console.log(a % b);  // 1 取余
console.log(a ** 2); // 100 指数
console.log(a++);    // 10 后置递增(先输出后计算)
console.log(++a);    // 11 前置递增

2. 赋值运算符

let x = 5;
x += 3;  // 等价于 x = x + 3 → 8
x **= 2; //  等价于 x = x ** 2,x = 5² → 25

3. 比较运算符

5 == '5'   // true → 值相等(自动类型转换)
5 === '5'  // false → 严格相等(值和类型)
NaN === NaN // false → 特殊:NaN不等于自身
NaN == NaN //false
Object.is(NaN, NaN) // true → ES6精准判断

4. 逻辑运算符

true && false  // false → 与(短路特性)
0 || "default" // "default" → 或(返回第一个真值)0是false的
1 || "default" // 1
1 && 5 //5,因为两个都是真值,所以返回后面的5!!
!true          // false → 非

5. 位运算符

核心规则:

  • 位运算会将数值转换为 32 位二进制整数(超出 32 位的部分会被丢弃),然后对每一位进行运算。
  • 运算后结果会转回十进制显示
5 & 1   // 1 → 二进制 0101 & 0001 结果是 0001(1)
5 | 2   // 7 → 0101 | 0010 结果是0111(7)
5 << 1  // 10 → 左移1位(乘2) 0101向左移动一位就是 1010(10)
关键运算符
运算符名称规则(按位操作)
&按位与会对每一位进行比较,如果两个对应的位都为 1,则结果为 1,否则为 0
|按位或会对每一位进行比较,如果两个对应的位中至少有一个为 1,则结果为 1,否则为 0
<<左移会将二进制数的所有位向左移动指定的位数,右边空出的位用 0 填充。

6. 三元运算符

const status = age >= 18 ? '成人' : '未成年';

7. 其他运算符

typeof 'hello'   // 'string' → 类型检测
'hello' instanceof String // false(字面量非对象)
const arr = [...[1,2], ...[3,4]] // [1,2,3,4] → 展开运算符

-优先级金字塔(常见运算符)

优先级运算符示例
20() 分组(1 + 2) * 3
18++ -- 后置递增/减a++
17! ~ 逻辑非/位非!false
16** 指数2 ** 3 → 8
15* / %6 % 4 → 2
13+ -3 + 5 → 8
10<< >> 位移4 << 1 → 8
9> < 比较5 > 3 → true
6== === 相等判断5 === 5 → true
5&& 逻辑与a && b
4`
3?: 三元a ? b : c
2= 赋值x = 5

-高频考点解析

1. 严格相等陷阱
null == undefined  // true(特殊规则)值都是没有
null === undefined // false(类型不同)
2. 逻辑运算符妙用
// 设置默认值
const port = config.port || 8080;

// 条件执行
isLogin && showUserMenu();
3. 运算符优先级实战
2 + 3 * 4   // 14(乘法优先)
(2 + 3) * 4 // 20(括号改变优先级)

避坑指南
  1. 浮点运算精度

    0.1 + 0.2 === 0.3 // false → 存储精度问题
    // 解决方案:使用toFixed或放大为整数运算
    const sum = 0.1 + 0.2;
    console.log(sum.toFixed(2)); // "0.30" (返回字符串)
    //2是保留2位小数,注意返回的是字符串,想要小数可以墙砖Number()
    // 转换为数字
    console.log(Number(sum.toFixed(2))); // 0.3
    console.log(+sum.toFixed(2)); // 0.3
    
  2. 短路运算边界条件

    0 || 1   // 1(0为false值)
    "" && 5  // ""(空字符串为false)
    
  3. 类型转换陷阱 (很容易掉坑的地方!!)

    "5" - 3  // 2(字符串转数字)
    "5" + 3  // "53"(数字转字符串拼接)
    

1.4JavaScript 流程控制语句详解

一、条件语句

1. if 语句
let age = 18;

// 基础形式
if (age >= 18) {
  console.log("已成年");
}

// if-else
if (age >= 18) {
  console.log("可以进入网吧");
} else {
  console.log("禁止进入");
}

// 多条件分支
if (age < 13) {
  console.log("儿童");
} else if (age < 18) {
  console.log("青少年");
} else {
  console.log("成年人");
}

注意事项

  • 建议始终使用代码块 {} 包裹语句
  • 条件表达式会自动转换布尔值
  • 判断相等推荐使用 ===
2. switch 语句
let day = 3;
let dayName;

switch(day) {
  case 1:
    dayName = "星期一";
    break;
  case 2:
    dayName = "星期二";
    break;
  case 3:
    dayName = "星期三";
    break;
  default:
    dayName = "未知";
}

console.log(dayName); // 星期三

//特别易错点在break这里
 let day = 1;
  let dayName;
  switch (day) {
    case 1:
      dayName = "星期一";
    case 2:
      dayName = "星期二";
    case 3:
      dayName = "星期三";
    default:
      dayName = "未知";
  }
  console.log(dayName); // 未知
/*
这是因为在 switch 语句中,每个 case 后缺少了 break,导致代码产生了“穿透”(fall-through)现象。具体流程如下:
当 day = 1 时,会匹配第一个 case 1,此时 dayName 被正确赋值为“星期一”。
由于没有 break,代码不会跳出 switch,而是继续执行后续的 case 2,将 dayName 覆盖为“星期二”。
继续穿透到 case 3,再次覆盖为“星期三”。
最终穿透到 default,覆盖为“未知”。
*/
//把default换位置!!结果也是被星期三覆盖了
  let day = 1;
    let dayName;
    switch (day) {
      case 1:
        dayName = "星期一";
      case 2:
        dayName = "星期二";
      default:
        dayName = "未知";
      case 3:
        dayName = "星期三";
    }
    console.log(dayName); // 星期三

关键特性

  • 使用 === 严格比较
  • 必须使用 break 阻止穿透
  • default 可放在任意位置

二、循环语句

1. while 循环
// 基础形式
let i = 0;
while (i < 5) {
  console.log(i);
  i++;
}
//0 1 2 4

// 特殊用法
let count = 3;
while (count--) {
  console.log(`剩余次数:${count}`);
}
// 输出:
// 剩余次数:2
// 剩余次数:1
// 剩余次数:0
2. do-while 循环
let x = 0;
do {
  console.log(x);
  x++;
} while (x < 3);
// 保证至少执行一次
3. for 循环
// 经典形式
for (let i = 0; i < 5; i++) {
  console.log(i);
}

// 特殊用法
for (let i = 0, j = 10; i < j; i++, j--) {
  console.log(i, j);
}

注意事项

  • 循环变量建议使用 let 声明
  • 避免修改循环变量值
  • 可省略任意表达式 for(;;)

三、循环控制

1. break 关键字
// 终止整个循环
for (let i = 0; i < 10; i++) {
  if (i === 5) {
    break;
  }
  console.log(i); // 输出 0-4
}
2. continue 关键字
// 跳过本次迭代
for (let i = 0; i < 5; i++) {
  if (i === 2) {
    continue;
  }
  console.log(i); // 输出 0,1,3,4
}
3. 标签语句(高级用法)
outerLoop: 
for (let i = 0; i < 3; i++) {
  innerLoop:
  for (let j = 0; j < 3; j++) {
    if (i === 1 && j === 1) {
      break outerLoop; // 直接终止外层循环
    }
    console.log(i, j);
  }
}
// 输出:
// 0 0
// 0 1
// 0 2
// 1 0

四、特殊循环方法

1. for…of 循环
// 遍历可迭代对象
const colors = ["red", "green", "blue"];
for (const color of colors) {
  console.log(color);
}//换成let,var也是一样的
//red green blue
2. for…in 循环
// 遍历对象属性
const obj = {a:1, b:2, c:3};
for (const key in obj) {
  console.log(key, obj[key]);
}
//a 1
//b 2
//c 3
const obj = {
a: { name: 'a' }, 
b: { name: 'b' },
c: 3 
  };
for (const key in obj) {
console.log(key, obj[key]);
}

在这里插入图片描述

重要区别

特性for…offor…in
适用对象可迭代对象(数组等)对象
返回值元素值属性名
原型链属性不遍历会遍历

五、常见错误示例

1. 死循环
// ❌ 错误示范
let n = 0;
while (n < 5) {
  console.log(n);
  // 忘记修改循环变量
}
2. 错误的作用域
// ❌ 错误示范
for (var i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i); // 总是输出 3
  }, 100);
}

// ✅ 正确写法
for (let i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i); // 正确输出 0,1,2
  }, 100);
}
//这两个笔试的时候也会考到知识点哦!
  • 作用域问题var 是函数作用域,循环中的 i 被提升到全局(或外层函数作用域),所有异步回调共享同一个 i
  • 异步时序:当 setTimeout 回调执行时,循环早已结束,此时 i 的值已变为 3。
  • 块级作用域let 为每次循环创建一个新的块级作用域,每次迭代的 i 都是独立的副本。
  • 闭包捕获:每个 setTimeout 回调捕获的是对应迭代时的 i 值,因此输出符合预期。

六、最佳实践建议

  1. 优先使用 for 循环 处理已知次数的迭代
  2. 慎用 while 处理不确定次数的循环时设置安全计数器
  3. 合理使用 break/continue 但避免过度使用
  4. 循环嵌套不超过3层 超过时应考虑拆分函数
  5. 及时释放资源 在循环结束后清理不需要的变量
// 性能优化示例
const bigArray = new Array(1000000).fill(0);

// ❌ 低效写法
for (let i = 0; i < bigArray.length; i++) {
  // 每次循环都读取数组长度
}

// ✅ 高效写法
const length = bigArray.length;
for (let i = 0; i < length; i++) {
  // 预先缓存数组长度
}

流程图示例:

true
yes
no
yes
no
false
开始循环
条件判断
执行循环体
执行continue?
执行break?
结束循环
更新循环变量

二、DOM 与 BOM

终究是来到了我们的bom跟dom了。

一、什么是 DOM?

1. 基本定义

DOM(Document Object Model)是浏览器将 HTML/XML 文档解析成的树形结构模型。简单说:
👉 DOM = 网页的编程接口
👉 DOM = 操作网页内容的API集合

2.Dom树 直观图示

Document
html
head
body
title
div1
div2
p1
p2
img
主要功能
功能类型具体操作示例
内容操作修改文本、添加/删除元素
样式控制修改颜色、大小、显示状态
事件响应点击、滚动、键盘输入等交互处理
数据获取获取表单数据、元素属性
<div id="box" class="container">内容</div>
// 节点操作
const box = document.getElementById('box');
const newDiv = document.createElement('div');
box.appendChild(newDiv);

// 样式操作
box.style.backgroundColor = '#f00';
box.classList.add('active');

// 属性操作
box.setAttribute('data-id', 123);
console.log(box.getAttribute('data-id')); // 123

在这里插入图片描述

(1) 获取元素
// 通过ID获取(返回单个元素)
const header = document.getElementById('header');
// 通过类名获取(返回集合)
const boxes = document.getElementsByClassName('box');
// 通过标签名获取(返回集合)
const imgs = document.getElementsByTagName('img');
// 现代选择器(返回第一个匹配元素)
const btn = document.querySelector('.submit-btn');
// 获取所有匹配元素
const items = document.querySelectorAll('.list-item');
(2) 修改内容
// 修改文本内容
const title = document.querySelector('h1');
title.textContent = '新标题';

// 修改HTML内容(注意安全风险)
const container = document.getElementById('container');
container.innerHTML = '<p>动态内容</p>';

// 安全插入内容
const safeDiv = document.createElement('div');
safeDiv.textContent = userInput; // 自动转义特殊字符
container.appendChild(safeDiv);
(3) 样式操作
const box = document.querySelector('.box');

// 直接修改样式box.style
box.style.backgroundColor = '#f00';
box.style.fontSize = '20px';

// 切换类名box.classList
box.classList.add('active');
box.classList.remove('old-class');
box.classList.toggle('hidden');

// 获取计算样式
const computedStyle = window.getComputedStyle(box);
console.log(computedStyle.width);

3. 节点关系操作

const parent = document.querySelector('.parent');
const child = document.querySelector('.child');

// 父子关系
console.log(child.parentNode); // 获取父节点
console.log(parent.children); // 获取所有子元素

// 兄弟关系
console.log(child.previousElementSibling); // 前一个兄弟元素
console.log(child.nextElementSibling);    // 后一个兄弟元素

四、DOM 事件处理

1. 事件监听三要素

const btn = document.querySelector('#myButton');

// 1. 事件类型:'click'
// 2. 回调函数:handleClick
// 3. 触发元素:btn
btn.addEventListener('click', handleClick);

function handleClick(event) {
  console.log('按钮被点击了!');
  console.log(event.target); // 触发元素
}

2. 常用事件类型

事件类型触发时机
click鼠标点击
mouseover鼠标悬停
keydown键盘按下
submit表单提交
scroll滚动事件
load资源加载完成

五、DOM 操作性能优化

1. 高效操作建议

  1. 批量修改:使用文档片段减少重绘.

  2. DocumentFragment 是一个轻量级的「虚拟DOM容器」,具有以下特点:

    • 不在主DOM树中存在
    • 可以临时存储DOM节点
    • 批量插入时只触发一次重排(reflow)
    // ❌ 低效写法(触发100次重排)
    for (let i = 0; i < 100; i++) {
      const div = document.createElement('div');
      document.body.appendChild(div); // 每次都会触发页面重排
    }
    //✅ 高效写法
    // 1. 创建文档片段(内存中的虚拟容器)
    const fragment = document.createDocumentFragment();
    // 2. 批量创建元素(不会触发重排)
    for (let i = 0; i < 100; i++) {
      const div = document.createElement('div');
      div.textContent = `Item ${i}`;
      
      // 3. 将元素添加到片段(不在真实DOM中)
      fragment.appendChild(div);
    }
    
    // 4. 一次性插入DOM(仅触发1次重排)
    document.body.appendChild(fragment);
    // 操作完成后
    fragment = null;
    
    JavaScript DocumentFragment 真实DOM createDocumentFragment() appendChild(div) loop [100次] appendChild(fragment) 完成插入 JavaScript DocumentFragment 真实DOM
  3. 缓存查询结果:避免重复查询

    查询缓存是指将 DOM 查询结果保存到变量中,避免重复执行相同的查询操作。就像去图书馆找书:

    • ❌ 每次需要都重新查找(低效)
    • ✅ 找到后记下位置,下次直接取用(高效)
    // ❌ 错误方式
    for (let i = 0; i < 10; i++) {
      document.querySelector('.item').style.color = 'red';
    }
    //问题:执行了 10次完全相同的DOM查询,每次查询都要扫描整个文档树,性能损耗随循环次数指数级增长
    
    // ✅ 高效写法
    // 1. 一次性查询所有元素(仅扫描DOM一次)
    const items = document.querySelectorAll('.item');
    
    // 2. 使用缓存的结果进行操作
    items.forEach(item => {
      item.style.color = 'red'; // 直接使用已缓存元素
    });
    
    开始
    查询DOM
    存储到变量
    操作缓存元素
    结束
    开始
    每次操作都重新查询
    重复扫描DOM
    性能损耗
  4. 使用事件委托:减少事件监听器数量

    一、什么是事件委托?

    事件委托是一种利用事件冒泡机制的技术,通过将事件监听器设置在父元素上,来管理其所有子元素的事件响应。就像快递柜的运作方式:

    • ❌ 传统方式:给每个快递格单独装监控(为每个子元素绑定事件)
    • ✅ 事件委托:只在快递柜总台装监控(在父元素绑定事件)

    二、为什么需要事件委托?

    性能对比

    方式事件监听器数量内存占用动态元素支持
    传统绑定N个(子元素数)需要重新绑定
    事件委托1个(父元素)自动支持
    document.querySelector('.list').addEventListener('click', (e) => {
      if (e.target.matches('.item')) {
        console.log('点击了列表项');
      }
    });
    

六、DOM vs BOM

特性DOMBOM
作用对象文档内容浏览器窗口
核心对象documentwindow
包含内容页面元素操作浏览器历史、地址栏、屏幕信息
标准化W3C 标准浏览器厂商实现
65% 35% DOM/BOM 功能占比 DOM 操作 BOM 操作

一、什么是BOM?

BOM是浏览器提供的用于操作浏览器窗口的对象模型,与DOM(操作文档)不同,BOM主要控制:

  • 浏览器窗口尺寸/位置
  • 导航/历史记录
  • 屏幕信息
  • 弹窗对话框
  • 定时器
  • 本地存储等

二、核心对象及用法

1. window对象(全局对象)
// 获取窗口尺寸
const width = window.innerWidth;
const height = window.innerHeight;

// 打开新窗口
const newWindow = window.open('https://baidu.com', '_blank');

// 滚动控制
window.scrollTo(0, 500); // 滚动到指定位置
window.scrollBy(0, 100); // 相对滚动
2. location对象(地址栏控制)
// 获取当前URL信息
console.log(location.href);     // 完整URL
console.log(location.hostname); // 域名
console.log(location.pathname); // 路径

// 页面跳转
location.assign('https://new.com'); // 记录历史
location.replace('https://new.com'); // 不记录历史
location.reload(); // 重新加载

// 修改URL参数
location.search = '?page=2'; // 添加查询参数
3. history对象(导航历史)
// 导航控制
history.back();     // 后退
history.forward(); // 前进
history.go(-2);    // 后退2页

// 添加历史记录
history.pushState({page: 1}, "title 1", "?page=1");
history.replaceState({page: 2}, "title 2", "?page=2");
4. navigator对象(浏览器信息)
// 检测浏览器类型
const isChrome = /Chrome/.test(navigator.userAgent);

// 获取设备能力
console.log(navigator.onLine); // 是否联网
console.log(navigator.geolocation); // 地理位置API
console.log(navigator.clipboard); // 剪贴板API

// 检测移动设备
const isMobile = /Mobi|Android/i.test(navigator.userAgent);
5. screen对象(屏幕信息)
console.log(screen.width);      // 屏幕宽度
console.log(screen.height);     // 屏幕高度
console.log(screen.availWidth); // 可用宽度(除任务栏)
console.log(screen.colorDepth); // 颜色位数

三、实用功能详解

1. 弹窗控制
// 警告框
alert('警告信息');

// 确认框
if (confirm('确定删除?')) {
  console.log('已删除');
}

// 输入框
const name = prompt('请输入姓名', '张三');
2. 定时器
// 一次性定时器
const timer = setTimeout(() => {
  console.log('3秒后执行');
}, 3000);

// 清除定时器
clearTimeout(timer);

// 循环定时器
const interval = setInterval(() => {
  console.log('每秒执行');
}, 1000);

// 清除循环
clearInterval(interval);
3. 本地存储
// localStorage(永久存储)
localStorage.setItem('theme', 'dark');
console.log(localStorage.getItem('theme')); // "dark"
localStorage.removeItem('theme');

// sessionStorage(会话级存储)
sessionStorage.setItem('token', 'abc123');

// Cookie操作
document.cookie = "username=John; expires=Thu, 18 Dec 2023 12:00:00 UTC; path=/";

四、现代BOM API

1. 地理位置API
navigator.geolocation.getCurrentPosition(
  (pos) => {
    console.log(`纬度: ${pos.coords.latitude}`);
    console.log(`经度: ${pos.coords.longitude}`);
  },
  (err) => {
    console.error('获取位置失败:', err);
  }
);
2. 设备方向API
window.addEventListener('deviceorientation', (e) => {
  console.log(`Alpha: ${e.alpha}`); // 绕Z轴旋转
  console.log(`Beta: ${e.beta}`);   // 绕X轴旋转
  console.log(`Gamma: ${e.gamma}`); // 绕Y轴旋转
});
3. 网络状态API
// 检测网络变化
window.addEventListener('online', () => {
  console.log('网络已连接');
});

window.addEventListener('offline', () => {
  console.log('网络已断开');
});

六、注意事项

  1. 弹窗限制:现代浏览器会拦截非用户触发的弹窗
  2. 隐私API:如地理位置需要用户授权
  3. 兼容性问题:部分BOM特性在不同浏览器表现不同
  4. 内存泄漏:定时器需及时清除
45% 20% 15% 10% 5% 5% BOM使用频率 window对象 location对象 navigator对象 history对象 screen对象 其他

三、JavaScript 内置对象全面解析

一、基础内置对象

1. Array 数组对象

// 创建数组
const fruits = ['Apple', 'Banana'];

// 常用方法
fruits.push('Orange');       // 末尾添加
fruits.pop();                // 移除末尾
fruits.includes('Apple');    // 检查存在,返回布尔值
fruits.join(', ');           // 转为字符串
fruit=fruits.push('Orange');   
// 高阶函数
console.log([1,2,3].map(x=>x*2 ))  // [2, 4, 6]
console.log([1,2,3].filter(x => x > 1))// [2, 3]

2. String 字符串对象

const str = 'Hello World';

// 常用操作
str.indexOf('World');      // 6
str.slice(0, 5);           // 'Hello'
str.replace('World', 'JS');// 'Hello JS'
str.split(' ');            // ['Hello', 'World']

// 模板字符串
const name = 'Ac;
console.log(`Hello ${name}`); // Hello Ac

3. Math 数学对象

Math.PI;                   // 3.141592653589793
Math.round(4.7);           // 5
Math.random();             // 0-1随机数
Math.max(10, 20, 30);      // 30

// 生成区间随机数
function randomInRange(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
//Math.random():生成一个0(包括)到1(不包括)之间的随机小数。乘以 (max - min + 1):将随机小数扩展到所需的范围长度。Math.floor():将结果向下取整,得到一个整数。加 min:将结果调整到所需的最小值 min。
/*
示例:
console.log( randomInRange(1,5))
可能返回 1, 2, 3, 4, 或 5。
randomInRange(10, 20) 可能返回 10 到 20 之间的任意整数。
*/

二、日期和时间对象

Date 对象

// 创建日期
const now = new Date();
const birthday = new Date('1995-12-17');

// 日期操作
now.getFullYear();         // 当前年份
now.getMonth();            // 0-11 (0=一月)
now.toISOString();         // "2023-08-15T12:00:00.000Z"

// 日期格式化
now.toLocaleDateString('zh-CN', { 
  year: 'numeric', 
  month: 'long', 
  day: 'numeric' 
}); // "2023年8月15日"

三、键值对集合

1. Object 基础对象

const person = {
  name: 'John',
  age: 30,
  greet() {
    console.log(`Hello, ${this.name}`);
  }
};

// 操作属性
person.name = 'Alice';
delete person.age;
Object.keys(person); // ['name', 'greet']

2. Map 与 Set

// Map(键值对集合)
const map = new Map();
map.set('name', 'John');
map.get('name'); // 'John'

// Set(值唯一集合)
const set = new Set([1, 2, 3, 2]);
set.size; // 3 (自动去重)

四、JSON 处理

JSON 对象
const user = {
  name: "John",
  age: 30
};

// 序列化与反序列化
const jsonStr = JSON.stringify(user);
const parsedObj = JSON.parse(jsonStr);

// 格式化输出
JSON.stringify(user, null, 2);
/*
{
  "name": "John",
  "age": 30
}
*/

五、数据类型对象

1. Number

// 数字常量
Number.MAX_SAFE_INTEGER; // 9007199254740991

// 类型转换
Number('123'); // 123
(123).toString(); // '123'

// 数值格式化
(12345.6789).toFixed(2); // "12345.68"

2. Boolean

// 显式转换
Boolean('text'); // true
Boolean(0);      // false

// 隐式转换规则
!!'hello'; // true
!!0;       // false

六、特殊内置对象

1. RegExp 正则表达式

// 创建正则,下面第九节会清晰的讲解正则内容的
const regex = /\d+/g;// \d表示匹配数字

// 使用方法
'123abc'.match(regex); // ['123']
regex.test('123');     // 这是测试返回true

// 常用模式
/^[a-z]+$/i.test('Hello'); // 字母检查
/\d{4}-\d{2}-\d{2}/.test('2023-08-15'); // 日期格式检查

2. Error 错误对象

// 抛出错误
throw new Error('出错啦!');

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

// 错误处理
try {
  // 可能出错的代码
} catch (err) {
  console.error(err.name, err.message);
}

七、现代新增对象

1. Promise

// 创建Promise
const fetchData = new Promise((resolve, reject) => {
  setTimeout(() => resolve('数据加载成功'), 1000);
});

// 使用Promise
fetchData
  .then(data => console.log(data))
  .catch(err => console.error(err));

// async/await
async function getData() {
  try {
    const data = await fetchData;
    console.log(data);
  } catch (err) {
    console.error(err);
  }
}

2. Proxy

// 创建代理
const target = {};
const handler = {
  get(obj, prop) {
    return prop in obj ? obj[prop] : 37;
  }
};

const proxy = new Proxy(target, handler);
proxy.a = 1;
console.log(proxy.a, proxy.b); // 1, 37

八、对象关系图谱

JavaScript内置对象
基础类型
集合类型
功能对象
Number
String
Boolean
Array
Object
Map
Set
Date
Math
JSON
RegExp
Error

九、最佳实践建议

  1. 优先使用现代API:如Map代替Object用于键值对集合
  2. 注意类型转换:明确使用String()/Number()等转换方法
  3. 善用高阶函数:reduce/filter/map等替代传统循环
  4. 合理使用扩展运算符:[…arr], {…obj}等语法糖
  5. 注意浏览器兼容性:如Proxy等新特性需考虑兼容

掌握这些内置对象,可以显著提升JavaScript开发效率和质量!

四、JavaScript 事件系统全面指南

一、事件基础概念

1. 什么是事件?

事件是发生在HTML元素上的"事情",比如:

  • 用户操作(点击、滚动、按键)
  • 浏览器行为(页面加载、窗口大小变化)
  • 网络活动(AJAX请求完成)

2. 事件三要素

element.addEventListener('click', function(event) {
  // 1. 事件类型:'click'
  // 2. 事件目标:element
  // 3. 事件对象:event
});

二、事件绑定方式

1. HTML属性方式(不推荐)

<button onclick="handleClick()">点击</button>

2. DOM属性方式

document.getElementById('myBtn').onclick = function() {
  console.log('按钮被点击');
};

3. addEventListener(推荐)

const btn = document.querySelector('#myBtn');

// 可以添加多个同类型事件
btn.addEventListener('click', handleClick);
btn.addEventListener('click', function() {
  console.log('第二个点击处理');
});

三、事件流机制

1. 三个阶段

捕获阶段
目标阶段
冒泡阶段

2. 代码示例

document.querySelector('.outer').addEventListener(
  'click', 
  () => console.log('捕获阶段'),
  true // 使用捕获
);

document.querySelector('.inner').addEventListener(
  'click', 
  () => console.log('冒泡阶段') 
  // 默认冒泡阶段
);

四、事件对象(Event)

1. 常用属性

element.addEventListener('click', function(event) {
  event.target;    // 触发事件的元素
  event.currentTarget; // 绑定事件的元素
  event.type;      // 事件类型
  event.clientX;   // 鼠标X坐标
  event.key;       // 按键值
});

2. 常用方法

event.preventDefault(); // 阻止默认行为
event.stopPropagation(); // 停止事件传播
event.stopImmediatePropagation(); // 阻止其他监听器执行

五、常见事件类型

1. 鼠标事件

事件类型触发条件
click点击(按下并释放)
dblclick双击
mousedown鼠标按下
mouseup鼠标释放
mousemove鼠标移动
mouseenter鼠标进入
mouseleave鼠标离开

2. 键盘事件

document.addEventListener('keydown', (e) => {
  console.log(`按下键: ${e.key}, 代码: ${e.code}`);
});

3. 表单事件

const form = document.querySelector('form');
form.addEventListener('submit', (e) => {
  e.preventDefault(); // 阻止表单提交
  // 表单验证逻辑
});

4. 窗口事件

window.addEventListener('resize', () => {
  console.log(`窗口大小: ${window.innerWidth}x${window.innerHeight}`);
});

window.addEventListener('scroll', () => {
  console.log(`滚动位置: ${window.scrollY}`);
});

六、事件委托模式

1. 传统方式的问题

// 为每个列表项绑定事件
document.querySelectorAll('.item').forEach(item => {
  item.addEventListener('click', handleClick);
});

2. 事件委托解决方案

// 只需一个事件监听器
document.querySelector('.list').addEventListener('click', (e) => {
  if (e.target.matches('.item')) {
    console.log('点击了项目:', e.target.dataset.id);
  }
});

七、自定义事件

1. 创建和触发

// 创建自定义事件
const event = new CustomEvent('myEvent', {
  detail: { message: 'Hello World' }
});

// 监听事件
document.addEventListener('myEvent', (e) => {
  console.log(e.detail.message);
});

// 触发事件
document.dispatchEvent(event);

2. 元素级自定义事件

const button = document.querySelector('button');

button.addEventListener('alert', (e) => {
  alert(e.detail.message);
});

button.dispatchEvent(new CustomEvent('alert', {
  detail: { message: '按钮事件触发!' }
}));

八、性能优化

1. 防抖(Debounce)

function debounce(func, delay) {
  let timer;
  return function() {
    clearTimeout(timer);
    timer = setTimeout(() => func.apply(this, arguments), delay);
  };
}

window.addEventListener('resize', debounce(() => {
  console.log('窗口大小变化');
}, 200));

2. 节流(Throttle)

function throttle(func, limit) {
  let lastRun;
  return function() {
    if (!lastRun || (Date.now() - lastRun >= limit)) {
      func.apply(this, arguments);
      lastRun = Date.now();
    }
  };
}

document.addEventListener('scroll', throttle(() => {
  console.log('滚动事件');
}, 100));

九、事件最佳实践

  1. 优先使用addEventListener:比on属性方式更灵活
  2. 及时移除事件监听:避免内存泄漏
    function handleClick() {}
    element.addEventListener('click', handleClick);
    // 不再需要时
    element.removeEventListener('click', handleClick);
    
  3. 合理使用被动事件:提升滚动性能
    window.addEventListener('scroll', () => {}, { passive: true });
    
  4. 避免过度事件委托:深层嵌套结构可能影响性能

十、现代事件处理

1. AbortController

const controller = new AbortController();

element.addEventListener('click', () => {
  console.log('点击事件');
}, { signal: controller.signal });

// 取消所有通过该controller注册的事件
controller.abort();

2. 事件处理选项

// 只执行一次的事件
element.addEventListener('click', () => {
  console.log('只会执行一次');
}, { once: true });

// 捕获阶段事件
element.addEventListener('click', () => {}, { capture: true });

五、AJAX 全面指南:现代前端数据交互技术

一、AJAX 基础概念

1. 什么是 AJAX?

AJAX(Asynchronous JavaScript and XML)是一种异步的 Web 开发技术,允许:

  • 不刷新页面的情况下与服务器交换数据
  • 局部更新网页内容
  • 异步执行网络请求(不会阻塞页面)

2. 核心优势

传统方式AJAX 方式
完整页面刷新局部更新
同步请求异步请求
用户体验中断流畅交互

二、XMLHttpRequest 基础

1. 基本使用流程

const xhr = new XMLHttpRequest();

xhr.open('GET', 'https://api.example.com/data', true); // 异步请求

xhr.onreadystatechange = function() {
  if (xhr.readyState === 4 && xhr.status === 200) {
    console.log(JSON.parse(xhr.responseText));
  }
};

xhr.send();

2. readyState 状态码

状态描述
0UNSENT代理被创建,但尚未调用 open()
1OPENEDopen() 方法已经被调用
2HEADERS_RECEIVEDsend() 方法已被调用,响应头已接收
3LOADING下载响应体中
4DONE请求操作已完成

三、Fetch API(现代替代方案)

1. 基本用法

fetch('https://api.example.com/data')
  .then(response => {
    if (!response.ok) {
      throw new Error('网络响应异常');
    }
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error('请求失败:', error));

2. 带参数的请求

// POST 请求示例
fetch('https://api.example.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token123'
  },
  body: JSON.stringify({
    username: 'john',
    password: 'secret'
  })
});

四、异步处理演进

1. 回调函数方式

function getData(callback) {
  const xhr = new XMLHttpRequest();
  xhr.onload = function() {
    callback(JSON.parse(xhr.responseText));
  };
  xhr.open('GET', 'api/data');
  xhr.send();
}

2. Promise 方式

function getData() {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.onload = () => resolve(JSON.parse(xhr.responseText));
    xhr.onerror = () => reject(xhr.statusText);
    xhr.open('GET', 'api/data');
    xhr.send();
  });
}

3. async/await(推荐)

async function loadData() {
  try {
    const response = await fetch('api/data');
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('加载失败:', error);
  }
}

五、实际应用场景

1. 表单提交

document.querySelector('form').addEventListener('submit', async (e) => {
  e.preventDefault();
  
  const formData = new FormData(e.target);
  const response = await fetch('/submit', {
    method: 'POST',
    body: formData
  });
  
  const result = await response.json();
  showNotification(result.message);
});

2. 无限滚动

window.addEventListener('scroll', throttle(async () => {
  if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 500) {
    const newData = await loadMoreItems();
    appendItemsToDOM(newData);
  }
}, 200));

六、错误处理与调试

1. 全面的错误处理

async function fetchWithRetry(url, retries = 3) {
  try {
    const response = await fetch(url);
    if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
    return await response.json();
  } catch (error) {
    if (retries <= 0) throw error;
    await new Promise(resolve => setTimeout(resolve, 1000));
    return fetchWithRetry(url, retries - 1);
  }
}

2. 调试技巧

// 查看请求详情
fetch('api/data')
  .then(response => {
    console.log('Headers:', [...response.headers.entries()]);
    console.log('Status:', response.status);
    return response.json();
  });

// 使用浏览器开发者工具
// Network 面板查看请求/响应

七、性能优化

1. 请求取消

const controller = new AbortController();

fetch('api/data', {
  signal: controller.signal
}).catch(e => {
  if (e.name === 'AbortError') {
    console.log('请求被取消');
  }
});

// 取消请求
controller.abort();

2. 数据缓存

const cache = new Map();

async function getCachedData(url) {
  if (cache.has(url)) return cache.get(url);
  
  const data = await fetch(url).then(res => res.json());
  cache.set(url, data);
  return data;
}

八、安全实践

1. CSRF 防护

// 自动添加CSRF令牌
fetch('/api/data', {
  headers: {
    'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
  }
});

2. CORS 处理

// 带凭证的请求
fetch('https://api.example.com', {
  credentials: 'include'
});

// 预检请求处理
const response = await fetch('https://api.example.com', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Custom-Header': 'value'
  },
  body: JSON.stringify(data)
});

九、现代替代方案

1. Axios 库

import axios from 'axios';

// 简洁的API
axios.get('/api/data')
  .then(response => console.log(response.data));

// 拦截器
axios.interceptors.response.use(
  response => response,
  error => {
    if (error.response.status === 401) {
      redirectToLogin();
    }
    return Promise.reject(error);
  }
);

2. GraphQL 请求

fetch('/graphql', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    query: `{
      user(id: "1") {
        name
        email
      }
    }`
  })
})
.then(res => res.json())
.then(data => console.log(data.data.user));

十、最佳实践总结

  1. 优先使用 Fetch API 或现代库(如 Axios)
  2. 始终处理错误 使用 try/catch 或 catch()
  3. 合理使用异步模式 async/await 提升可读性
  4. 考虑安全性 处理 CSRF、CORS 等问题
  5. 优化性能 实现缓存、请求取消等功能
  6. 保持代码整洁 封装通用请求函数
简单请求
复杂需求
发起请求
请求方式?
直接使用Fetch
使用Axios等库
处理响应
成功?
处理数据
错误处理

六、JavaScript 正则表达式完全指南

一、正则表达式基础

1. 创建正则表达式

// 字面量形式(推荐)
const regex1 = /pattern/flags;

// 构造函数形式
const regex2 = new RegExp('pattern', 'flags');

2. 常用匹配方法

// test() 方法
/hello/.test('hello world'); // true

// exec() 方法
const result = /world/.exec('hello world');
console.log(result[0]); // "world"

二、核心语法详解

1. 元字符

元字符说明示例
.匹配任意单个字符/.a/ 匹配 “ba”
\d数字 [0-9]/\d/ 匹配 “5”
\w单词字符 [A-Za-z0-9_]/\w/ 匹配 “a”
\s空白字符/\s/ 匹配 " "
^字符串开头/^A/ 匹配 "A"开头
$字符串结尾/z$/ 匹配 "z"结尾

2. 量词

量词说明示例
*0次或多次/a*/ 匹配 “aaa”
+1次或多次/a+/ 匹配 “aa”
?0次或1次/a?/ 匹配 “” 或 “a”
{n}恰好n次/a{2}/ 匹配 “aa”
{n,}至少n次/a{2,}/ 匹配 “aaa”
{n,m}n到m次/a{2,4}/ 匹配 “aaa”

三、实用技巧与示例

1. 分组与捕获

// 捕获分组
const phoneMatch = /(\d{3})-(\d{4})-(\d{4})/.exec('010-1234-5678');
console.log(phoneMatch[1]); // "010"

// 非捕获分组
/(?:\d{3})-(\d{4})/.exec('010-1234');

2. 贪婪与非贪婪匹配

// 贪婪匹配(默认)
'<div>content</div>'.match(/<.*>/)[0]; // "<div>content</div>"

// 非贪婪匹配
'<div>content</div>'.match(/<.*?>/)[0]; // "<div>"

3. 前瞻断言

// 正向肯定前瞻
'100 dollars'.match(/\d+(?= dollars)/)[0]; // "100"

// 正向否定前瞻
'100 pesos'.match(/\d+(?! dollars)/)[0]; // "100"

四、字符串方法中的应用

1. String.prototype.match()

const str = 'The rain in Spain';
const matches = str.match(/ain/g);
console.log(matches); // ["ain", "ain"]

2. String.prototype.replace()

// 简单替换
'Hello World'.replace(/world/i, 'JavaScript'); // "Hello JavaScript"

// 使用函数替换
'123-4567'.replace(/\d+/g, match => `(${match})`); // "(123)-(4567)"

3. String.prototype.split()

'2023-08-15'.split(/-/); // ["2023", "08", "15"]

五、常见实用正则

1. 邮箱验证

const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
emailRegex.test('user@example.com'); // true

2. 手机号验证(中国大陆)

const mobileRegex = /^1[3-9]\d{9}$/;
mobileRegex.test('13812345678'); // true

3. URL 提取

const urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;
urlRegex.test('https://www.example.com/path?query=string'); // true

六、性能优化

1. 预编译正则

// 需要多次使用的正则应该预编译
const precompiledRegex = /pattern/g;

for (let i = 0; i < 1000; i++) {
  precompiledRegex.test(inputString);
}

2. 避免回溯灾难

// 糟糕的正则 - 可能导致性能问题
/(a+)*b/.test('aaaaaaaaaaaaaaaaaaaaac'); // 可能很慢

// 改进版本
/a+b/.test('aaaaaaaaaaaaaaaaaaaaac'); // 效率更高

七、浏览器兼容性

1. ES6+ 新特性

特性ChromeFirefoxSafariEdge
u flag555010.115
s flag627811.179
命名捕获组647811.179

2. 兼容性写法

// 命名捕获组兼容方案
const namedGroupRegex = /(?<year>\d{4})-(?<month>\d{2})/;
const fallbackRegex = /(\d{4})-(\d{2})/;

const match = (str.match(namedGroupRegex) || str.match(fallbackRegex));
const { year = match[1], month = match[2] } = match.groups || {};

八、调试工具与技巧

1. 可视化工具

  • Regex101
  • RegExr

2. 控制台调试

// 查看正则对象的属性
console.dir(/pattern/g);

// 测试多个匹配
const regex = /\d+/g;
let match;
while ((match = regex.exec('123 456 789')) {
  console.log(match[0]);
}

九、最佳实践

  1. 添加注释:复杂正则使用 x 标志添加注释

    const regex = /
      ^\d{3}    # 前3位数字
      -\d{2}     # 中间2位数字
      -\d{4}$    # 最后4位数字
    /x;
    
  2. 优先可读性:复杂正则拆分为多个简单正则

  3. 充分测试:覆盖各种边界情况

  4. 性能考量:避免灾难性回溯

  5. 适时使用工具:可视化工具辅助编写复杂正则

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2321376.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Boot3 配置文件

统一配置文件管理 SpringBoot工程下&#xff0c;进行统一的配置管理&#xff0c;你想设置的任何参数&#xff08;端口号、项目根路径、数据库连接信息等等)都集中到一个固定位置和命名的配置文件&#xff08;application.properties或application.yml&#xff09;中&#xff0…

消防设施操作员考试:巧用时间高效备考攻略

合理规划时间是备考消防设施操作员考试的关键&#xff0c;能让学习事半功倍。​ 一、制定详细时间表​ 根据备考时间和考试内容&#xff0c;制定每日、每周的学习计划。将学习时间合理分配给理论知识学习、技能实操练习和模拟考试。例如&#xff0c;每天安排 3 - 4 小时学习理…

深度学习技术与应用的未来展望:从基础理论到实际实现

深度学习作为人工智能领域的核心技术之一&#xff0c;近年来引起了极大的关注。它不仅在学术界带来了革命性的进展&#xff0c;也在工业界展现出了广泛的应用前景。从图像识别到自然语言处理&#xff0c;再到强化学习和生成对抗网络&#xff08;GAN&#xff09;&#xff0c;深度…

FastStoneCapture下载安装教程(附安装包)专业截图工具

文章目录 前言FastStoneCapture下载FastStoneCapture安装步骤FastStoneCapture使用步骤 前言 在日常工作与学习里&#xff0c;高效截图工具至关重要。本教程将为你呈现FastStoneCapture下载安装教程&#xff0c;助你轻松拥有。 FastStoneCapture下载 FastStone Capture 是一款…

26考研——图_图的遍历(6)

408答疑 文章目录 三、图的遍历图的遍历概述图的遍历算法的重要性图的遍历与树的遍历的区别图的遍历过程中的注意事项避免重复访问遍历算法的分类遍历结果的不唯一性 广度优先搜索广度优先搜索&#xff08;BFS&#xff09;概述BFS 的特点广度优先遍历的过程示例图遍历过程 BFS …

C++类与对象的第一个简单的实战练习-3.24笔记

在哔哩哔哩学习的这个老师的C面向对象高级语言程序设计教程&#xff08;118集全&#xff09;讲的真的很不错 实战一&#xff1a; 情况一&#xff1a;将所有代码写到一个文件main.cpp中 #include<iostream> //不知道包含strcpy的头文件名称是什么,问ai可知 #include<…

4.1 C#获取目录的3个方法的区别

C#中常用有如下3个获取目录的方式如下 1.Directory.GetCurrentDirectory():获取当前工作目录&#xff0c;工作目录可能被用户或其他代码修改。尽量少用。&#xff08;似乎只要在运行中使用另存为或者打开某个文件夹&#xff0c;当前工作目录就修改&#xff09; 2.Application…

oracle数据库(数据库启动关闭/sqlplus登录及基本操作/设置字符集/distinct去重)

目录 1. Oracle数据库启动 2. Oracle数据库关闭 3. sqlplus登录Oracle数据库 3.1 使用sqlplus登录Oracle数据库 3.2 使用sqlplus登录Oracle数据库 3.3 远程登录 3.4 解锁用户 3.5 修改用户密码 3.6 查看当前语言环境 4. sqlplus基本操作 4.1 显示当前用户 4.2 查看当前用户…

1、SpringBoot集成MyBatis

&#xff08;1&#xff09;创建SpringBoot项目 &#xff08;2&#xff09;集成MyBatis 导入坐标 <!-- 连接数据库&#xff0c;版本5 --> <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><versi…

Linux实操篇-权限管理

目录 传送门前言一、权限管理概念二、权限管理实战1. Linux文件权限模型1.1 文件的三种基本权限1.2 权限的三类主体 2. 查看文件权限3. 修改文件权限3.1 使用符号方式修改权限3.2 使用数字方式修改权限 4. 特殊权限4.1 SUID&#xff08;Set User ID&#xff09;4.2 SGID&#x…

阿里开源的免费数据集成工具——DataX

企业里真实的数据流转是什么样子的呢&#xff1f; 左侧描述了一个企业真实的样子&#xff0c;我们总是需要把数据从一个地方搬到另一个地方&#xff0c;最后就是搬来搬去搬成了一张张解不开的网。 右侧则表达了使用DataX为中心实现数据的同步。 什么是DataX DataX是一个异构…

【前端】使用 HTML、CSS 和 JavaScript 创建一个数字时钟和搜索功能的网页

文章目录 ⭐前言⭐一、项目结构⭐二、HTML 结构⭐三、CSS 样式⭐四、JavaScript 功能⭐五、运行效果⭐总结 标题详情作者JosieBook头衔CSDN博客专家资格、阿里云社区专家博主、软件设计工程师博客内容开源、框架、软件工程、全栈&#xff08;,NET/Java/Python/C&#xff09;、数…

地理信息可视化技术大全【WebGIS 教程一】

前言&#xff1a; 在当今数据驱动的时代&#xff0c;地理信息技术&#xff08;GIS&#xff09;和空间数据可视化已成为科学研究、商业决策和智慧城市建设的重要工具。随着Web技术的快速发展&#xff0c;基于浏览器端的地图渲染和地理信息处理能力显著增强&#xff0c;各类开源与…

SLAM十四讲【四】相机与图像

SLAM十四讲【四】相机与图像 SLAM十四讲【一】基本概念 SLAM十四讲【二】三维空间刚体运动 SLAM十四讲【三】李群与李代数 SLAM十四讲【四】相机与图像 SLAM十四讲【五】线性优化 SLAM十四讲【六】视觉里程计 SLAM十四讲【七】回环检测 SLAM十四讲【八】建图 文章目录 SLAM十四…

类和对象-运算符重载-C++

1.加号运算符重载 1.成员函数重载调用 函数的定义部分&#xff08;这里的person是返回值类型&#xff0c;不是说构造函数&#xff09; class person { public:person operator(person& p){person temp;temp.a this->a p.a;temp.b this->b p.b;return temp;}in…

2000-2019年各省地方财政耕地占用税数据

2000-2019年各省地方财政耕地占用税数据 1、时间&#xff1a;2000-2019年 2、来源&#xff1a;国家统计局、统计年鉴 3、指标&#xff1a;行政区划代码、地区、年份、地方财政耕地占用税 4、范围&#xff1a;31省 5、指标说明&#xff1a;耕地占用税是地方财政的一种税收&…

从零到一开发一款 DeepSeek 聊天机器人

AI聊天机器人 目标设计方案系统架构技术选型功能模块 实现代码环境配置安装依赖 核心代码API 请求函数主循环函数 功能扩展1. 情感分析2. 多语言支持3. 上下文记忆4. 用户身份识别 总结附录 目标 开发一个智能聊天机器人&#xff0c;旨在为用户提供自然、流畅的对话体验。通过…

S32K144外设实验(五):FTM周期中断

文章目录 1. 概述1.1 时钟系统1.2 实验目的 2. 代码的配置 1. 概述 1.1 时钟系统 FTM的CPU接口时钟为SYS_CLK&#xff0c;在RUN模式下最高80MHz。模块的时钟结构如下图所示。 从上图中可以看出&#xff0c;FTM模块的功能时钟为SYS_CLK&#xff0c;计数器的时钟源可以来源于三…

Android 静态壁纸设置实现方案

提示&#xff1a;Android 平台&#xff0c;静态壁纸实现方案 文章目录 需求&#xff1a;Android 实现壁纸 设置场景 参考资料实现方案直接调用系统 API,WallpaperManager 来实现 wallpaperManager.setResource系统源码分析系统app WallpaperPickerWallpaperPickerActivity ->…

在计算进程D状态持续时间及等IO的时间遇到的一处问题

一、背景 之前的博客 线程每次iodelay监控及D状态开始和结束监控并做堆栈记录-CSDN博客 里&#xff0c;我们讲到了通过内核模块抓取D状态的进程和等IO事件的方法&#xff0c;里面也用到了通过获取rq的symbol&#xff0c;再去获取rq里的rq_clock_task时间的方法&#xff08;内核…