JavaScript Definitive Guide-Chapter 11 Notes QA
1、 理解 TypedArray 与 ArrayBuffer:共享内存机制详解
📘 示例代码
let ints = new Int16Array([0,1,2,3,4,5,6,7,8,9])
let last3 = ints.subarray(ints.length-3, ints.length)
ints
// Int16Array(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
last3
// Int16Array(3) [7, 8, 9]
ints[9] = -1
last3
// Int16Array(3) [7, 8, -1]
last3.buffer
// ArrayBuffer { [Uint8Contents]: <00 00 01 00 02 00 ... ff ff>, byteLength: 20 }
last3.buffer === ints.buffer
// true
last3.byteOffset
// 14
last3.byteLength
// 6
last3.buffer.byteLength
// 20
🧩 一、创建一个 16 位整数数组
let ints = new Int16Array([0,1,2,3,4,5,6,7,8,9])
- 每个元素占 2 字节(Int16 = 16 位)。
- 共 10 个数 → 总字节数 = 10 × 2 = 20 字节。
- 底层的 20 字节数据存在一个叫
ArrayBuffer的连续内存中。
✅ ints 只是对这块内存的一个“视图”。
🧠 二、从中“切”出一段子视图
let last3 = ints.subarray(ints.length - 3, ints.length)
表示从原数组第 7、8、9 个元素开始,
创建一个新视图 last3,对应 [7, 8, 9]。
⚠️
subarray()不会复制数据,只是创建一个“窗口”,
这个窗口仍然指向同一块底层内存。
🔄 三、共享内存效果
ints[9] = -1
修改原数组的最后一个元素后:
last3 // Int16Array(3) [ 7, 8, -1 ]
✅ last3 自动变化,因为它与 ints 共享同一块内存。
🧱 四、底层内存结构(ArrayBuffer)
last3.buffer === ints.buffer // true
说明两者共享同一个底层 ArrayBuffer。
| 属性 | 含义 | 值 |
|---|---|---|
last3.byteOffset |
从原内存起始位置偏移的字节数 | 14 |
last3.byteLength |
当前视图覆盖的字节长度 | 6 |
ints.buffer.byteLength |
整个底层内存大小 | 20 |
✅ 五、总结一句话
| 概念 | 通俗解释 |
|---|---|
ArrayBuffer |
一整块原始二进制内存 |
TypedArray(如 Int16Array) |
看这块内存的“窗口” |
subarray() |
不复制数据,只截取一段“视图” |
| 共享内存效果 | 改一个,另一个也会变 |
💡 类比理解
ArrayBuffer像是一整张 A4 纸Int16Array是你拿尺子量出来的 数据区域subarray()就是用透明片框出“纸上某一区域”- 改动纸上内容,所有透明片看到的部分都会变
2、 小端序(Little Endian)与大端序(Big Endian)解析
非常好的问题 👍
“小端序(Little Endian)”和“大端序(Big Endian)”其实就是在多字节数据里,计算机存储字节顺序的两种方式。
🧠 一句话解释
| 术语 | 含义 |
|---|---|
| 大端序(Big Endian) | 高位字节放在前面(低地址) |
| 小端序(Little Endian) | 低位字节放在前面(低地址) |
📘 举个最通俗的例子
假设有一个 32 位整数:
0x12345678
它占 4 个字节(每字节两个十六进制位):
12 34 56 78
| 存储方式 | 低地址 → 高地址的排列顺序 | 形象记忆 |
|---|---|---|
| 大端序(Big Endian) | 12 34 56 78 | 像人类写数字,从左到右 |
| 小端序(Little Endian) | 78 56 34 12 | 把“数字反着写”存进去 |
💡 比喻记忆法
- 大端序:把“大头”(高位)放前面,就像我们写数字“1234”,从高位写起。
- 小端序:把“小头”(低位)放前面,就像把数字“1234”倒着放成“4321”。
🧩 举个真实例子(JavaScript + DataView)
let buffer = new ArrayBuffer(4);
let view = new DataView(buffer);
// 小端序
view.setUint32(0, 0x12345678, true); // true 表示小端序
console.log(new Uint8Array(buffer)); // 输出: [120, 86, 52, 18] = 0x78 0x56 0x34 0x12
// 大端序
view.setUint32(0, 0x12345678, false);
console.log(new Uint8Array(buffer)); // 输出: [18, 52, 86, 120] = 0x12 0x34 0x56 0x78
✅ 总结一句话
| 端序 | 存储规则 | 直观印象 |
|---|---|---|
| 大端序 (Big Endian) | 高位在前,低位在后 | 像人类读写数字 |
| 小端序 (Little Endian) | 低位在前,高位在后 | 计算机常用方式(如 Intel CPU) |
🧭 所以说:
“端序”只是决定多字节数在内存中是正着放还是反着放,数据本身的数值是一模一样的,只是存放顺序不同而已。
32 位整数为什么占 4 个字节
非常好,这正是“位(bit)”和“字节(byte)”容易混淆的地方 👍
🧠 一、基本换算
1 字节(Byte) = 8 位(bit)
- 一个“位(bit)”就是一个二进制数字(0 或 1)
- 一个“字节(Byte)”就是 8 个二进制位
💡 二、32 位整数是啥意思?
“32 位”整数指的是这个整数用 32 个二进制位来存储。
计算它占多少字节:
32 位 ÷ 8 位/字节 = 4 字节
📘 三、举例:0x12345678
- 每个十六进制数字(0–F)正好对应 4 位二进制
- 共有 8 个十六进制数字 → 8 × 4 = 32 位 = 4 字节
| 表示方式 | 位数 | 字节数 |
|---|---|---|
| 0x12 | 8 位 | 1 字节 |
| 0x1234 | 16 位 | 2 字节 |
| 0x12345678 | 32 位 | 4 字节 |
🎯 四、形象比喻
想象你要装 32 个小球(bit),每个盒子(byte)能装 8 个小球,你就需要:
32 ÷ 8 = 4 个盒子
✅ 一句话总结:
“32 位整数”表示它占用 32 个二进制位(bit)来存储数据,而每 8 位是 1 字节(Byte),所以总共占 4 个字节(4 Bytes)。
为什么一个十六进制数字对应 4 个二进制位
🧠 一、二进制表示范围
| 二进制位数 | 能表示的范围 | 数量 |
|---|---|---|
| 1 位 | 0~1 | 2 种 |
| 2 位 | 00~11 | 4 种 |
| 3 位 | 000~111 | 8 种 |
| 4 位 | 0000~1111 | 16 种 |
💡 二、十六进制就是“16 进制”
十六进制(Hexadecimal)有 16 个符号:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F
| 十六进制 | 对应二进制(4位) |
|---|---|
| 0 | 0000 |
| 1 | 0001 |
| 2 | 0010 |
| 3 | 0011 |
| 4 | 0100 |
| 5 | 0101 |
| 6 | 0110 |
| 7 | 0111 |
| 8 | 1000 |
| 9 | 1001 |
| A | 1010 |
| B | 1011 |
| C | 1100 |
| D | 1101 |
| E | 1110 |
| F | 1111 |
📘 三、举例:0x12345678
- 8 个十六进制数字 × 4 位二进制 = 32 位 = 4 字节
✅ 总结:
因为 4 位二进制正好能表示 16 种情况(0~15),而十六进制正好有 16 个符号(0~F),所以 1 个十六进制数 = 4 个二进制位。
3、JavaScript 判断系统小端序示例解析
代码原文
let littleEndian = new Int8Array(new Int32Array([1]).buffer)[0] === 1;
逐步解析
-
new Int32Array([1])- 创建一个长度为 1 的 32 位整数数组。
- 数组内容是
[1]。 - 在内存中,这个整数
1会占 4 个字节(32 位)。
-
.bufferInt32Array是一个类型化数组(TypedArray)。.buffer属性返回其 底层的ArrayBuffer内存对象。ArrayBuffer可以用其他类型的视图来读取同一块内存。
-
new Int8Array(...).buffer- 将上面的 32 位整数的 buffer 包装成 8 位整数视图(Int8Array)。
- 8 位数组可以按字节读取内存里的内容。
- 因为
Int32Array占 4 个字节,Int8Array也会有 4 个元素。
-
[0]- 读取 8 位数组的第 0 个元素,也就是 内存中第一个字节的值。
-
=== 1- 判断第一个字节是否为
1。 - 如果 第一个字节是最低位(低地址存低位),说明系统是 小端序(Little Endian)。
- 如果第一个字节是
0,说明系统是 大端序(Big Endian)。
- 判断第一个字节是否为
总结一句话
let littleEndian = new Int8Array(new Int32Array([1]).buffer)[0] === 1;
意思就是:
通过检查 32 位整数
1的第一个字节,判断当前系统是否采用小端序存储。
true→ 小端序false→ 大端序
💡 形象记忆
- 小端序:低位(小头)先放 → 第一个字节 = 1
- 大端序:高位(大头)先放 → 第一个字节 = 0
4、JavaScript DataView 示例解析
代码原文
let bytes = new Uint8Array(1024);
let ints = new Uint32Array(bytes.buffer);
let floats = new Float64Array(bytes.buffer);
let view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
let int = view.getInt32(0);
int;
int = view.getInt32(4, false);
int;
int = view.getInt32(8, true);
view.setUint32(8, int, false);
逐步解析
1️⃣ 创建基础内存缓冲区
let bytes = new Uint8Array(1024);
- 创建一个长度为 1024 的 8 位无符号整数数组。
- 实际上就是申请了 1024 个字节的内存。
2️⃣ 创建其他类型数组视图
let ints = new Uint32Array(bytes.buffer);
let floats = new Float64Array(bytes.buffer);
-
bytes.buffer是底层的 ArrayBuffer(一块连续的内存)。 -
可以用不同的类型视图(TypedArray)来读取同一块内存:
Uint32Array:每 4 个字节组成一个 32 位无符号整数Float64Array:每 8 个字节组成一个 64 位浮点数
-
这样可以在不复制内存的情况下,用不同类型读取或写入数据。
3️⃣ DataView 的作用
let view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
-
DataView是一个 通用视图,可以在同一块内存上按任意偏移读取/写入多种类型数据。 -
与 TypedArray 不同的是:
- 可以指定字节偏移(offset)
- 可以灵活选择大端序或小端序(endianness)
-
常用于处理二进制协议或网络数据。
4️⃣ 使用 DataView 读取和写入数据
let int = view.getInt32(0);
getInt32(offset):从指定偏移读取 32 位有符号整数。- 如果没指定小端序,默认使用大端序。
int = view.getInt32(4, false);
- 第二个参数
false表示使用大端序(Big Endian)。
int = view.getInt32(8, true);
- 第二个参数
true表示使用小端序(Little Endian)。
view.setUint32(8, int, false);
setUint32(offset, value, littleEndian):在指定偏移写入 32 位无符号整数。- 第三个参数决定使用小端还是大端存储。
5️⃣ 总结
-
ArrayBuffer:内存本身
-
TypedArray(如 Uint8Array、Uint32Array):固定类型视图,按类型顺序访问内存
-
DataView:灵活视图,可按任意偏移读取/写入多种类型,并可控制端序
-
示例代码最终作用:
- 分配 1024 字节内存
- 用不同类型视图访问同一块内存
- 使用 DataView 精确读取/写入整数,控制端序
💡 小技巧:DataView 常用于解析二进制文件、网络协议或底层数据操作
5、正则表达式中的四种查找断言(Lookaround)通俗讲解
🧠 一句话概念
查找断言(Lookaround)就是一种“只看不吃”的规则:
它只检查前后是否满足条件,不真正匹配内容。
✅ 四种断言方式总览
| 类型 | 英文名 | 语法 | 含义 | 方向 |
|---|---|---|---|---|
| 正向肯定查找 | Positive Lookahead | (?=...) |
后面必须满足条件 | 向前(右看) |
| 正向否定查找 | Negative Lookahead | (?!...) |
后面不能满足条件 | 向前(右看) |
| 反向肯定查找 | Positive Lookbehind | (?<=...) |
前面必须满足条件 | 向后(左看) |
| 反向否定查找 | Negative Lookbehind | (?<!...) |
前面不能满足条件 | 向后(左看) |
🟢 1. 正向肯定查找 (?=...)
👉 意思:匹配某内容,要求它后面必须是……
let text = "100px 200em";
console.log(text.match(/\d+(?=px)/g)); // ['100']
解释:
匹配数字,但只有当后面紧跟 px 时才算成功。
200em 不符合。
🔴 2. 正向否定查找 (?!...)
👉 意思:匹配某内容,要求它后面不能是……
let text = "100px 200em";
console.log(text.match(/\d+(?!px)/g)); // ['200']
解释:
匹配数字,但后面 不是 px 的才算数。
🟢 3. 反向肯定查找 (?<=...)
👉 意思:匹配某内容,要求它前面必须是……
let text = "$100 €200";
console.log(text.match(/(?<=\$)\d+/g)); // ['100']
解释:
匹配数字,但只有当左边是 $ 时才匹配成功。
🔴 4. 反向否定查找 (?<!...)
👉 意思:匹配某内容,要求它前面不能是……
let text = "$100 €200";
console.log(text.match(/(?<!\$)\d+/g)); // ['200']
解释:
匹配数字,但前面 不是 $ 的才算。
🧭 一张图理解方向关系
←—— 向后看 ——┐
│
[A][B][C][D][E][F]
│
└—— 向前看 ——→
✅ 一句话总结
| 类型 | 检查方向 | 判断逻辑 | 示例效果 |
|---|---|---|---|
(?=...) |
向右看 | 后面必须满足 | 数字后面是 px |
(?!...) |
向右看 | 后面不能满足 | 数字后面不是 px |
(?<=...) |
向左看 | 前面必须满足 | 前面是 $ |
(?<!...) |
向左看 | 前面不能满足 | 前面不是 $ |
📘 记忆口诀:
✅ 肯定查找:要有;❌ 否定查找:不要有;
👀 向前查:看右边;👈 向后查:看左边。
6、JavaScript 正则表达式标志(Flags)详解
🧠 一句话概览
正则表达式的标志(flags)是写在表达式后面的修饰符,用来控制匹配方式。
常见 6 个标志:g,i,m,s,u,y
✅ 1. g —— 全局匹配(Global)
含义:
匹配字符串中所有符合条件的结果,而不是遇到第一个就停。
示例:
let text = "cat, cat, cat";
console.log(text.match(/cat/g)); // ['cat', 'cat', 'cat']
📘 没有 g:
console.log(text.match(/cat/)); // ['cat', index: 0, input: 'cat, cat, cat']
👉 只返回第一个匹配结果。
✅ 2. i —— 忽略大小写(Ignore Case)
含义:
匹配时不区分大小写。
示例:
let text = "Hello hello HELLO";
console.log(text.match(/hello/gi)); // ['Hello', 'hello', 'HELLO']
📘 没有 i:
console.log(text.match(/hello/g)); // ['hello']
✅ 3. m —— 多行匹配(Multiline)
含义:
让 ^ 和 $ 可以匹配每一行的开头与结尾,而不仅仅是整个字符串的开头与结尾。
示例:
let text = "apple\nbanana\ncherry";
console.log(text.match(/^b\w+/gm)); // ['banana']
📘 没有 m:
console.log(text.match(/^b\w+/g)); // null
✅ 4. s —— 单行模式(dotAll)
含义:
让点号 . 可以匹配换行符 \n。
默认情况下,. 不能匹配换行符。
示例:
let text = "hello\nworld";
console.log(text.match(/hello.world/s)); // ['hello\nworld']
📘 没有 s:
console.log(text.match(/hello.world/)); // null
✅ 5. u —— Unicode 模式(Unicode)
含义:
启用对 Unicode 字符的完整支持,让正则可以识别如 emoji、汉字等。
示例:
let text = "😊a";
console.log(text.match(/\p{Emoji}/u)); // ['😊']
📘 没有 u:
console.log(text.match(/\p{Emoji}/)); // 报错:Invalid escape
✅ 6. y —— 粘连匹配(Sticky)
含义:
匹配时从上一次匹配结束的位置继续开始,
不会跳过中间的字符(区别于 g)。
示例:
let text = "aaa_aaa_aaa";
let regex = /a+/y;
regex.lastIndex = 0;
console.log(regex.exec(text)); // ['aaa']
regex.lastIndex = 3;
console.log(regex.exec(text)); // null (因为中间有 '_' 断开)
📘 如果用 g:
let regex2 = /a+/g;
console.log(text.match(regex2)); // ['aaa', 'aaa', 'aaa']
🧭 总结对比表
| 标志 | 英文名 | 含义 | 示例效果 |
|---|---|---|---|
g |
global | 匹配所有结果 | 多次匹配 |
i |
ignoreCase | 忽略大小写 | A ≈ a |
m |
multiline | 多行匹配 | ^ $ 匹配行首行尾 |
s |
dotAll | . 匹配换行符 |
允许跨行匹配 |
u |
unicode | 支持 Unicode | 支持 emoji、汉字等 |
y |
sticky | 粘连匹配 | 从上次结束处继续 |
📘 一句话记忆口诀
g全局找,
i不分大小写,
m按行看,
s跨行点,
u懂 Unicode,
y粘着走不跳。
7、 📊 JavaScript console.table() 函数详解与示例
🧠 一句话概念
console.table()用来把数据以 表格形式 输出到控制台(Console),
比console.log()更直观、可读性更强。
📘 基本语法
console.table(data, columns);
| 参数名 | 类型 | 说明 |
|---|---|---|
data |
数组 或 对象 | 要显示的内容 |
columns |
数组(可选) | 指定要显示的列(字段名) |
🧩 示例 1:数组对象
let users = [
{ name: "Alice", age: 25, city: "Beijing" },
{ name: "Bob", age: 30, city: "Shanghai" },
{ name: "Cindy", age: 22, city: "Guangzhou" }
];
console.table(users);
输出效果(在浏览器控制台中):
| (index) | name | age | city |
|---|---|---|---|
| 0 | Alice | 25 | Beijing |
| 1 | Bob | 30 | Shanghai |
| 2 | Cindy | 22 | Guangzhou |
🧩 示例 2:只显示部分列
console.table(users, ["name", "city"]);
输出:
| (index) | name | city |
|---|---|---|
| 0 | Alice | Beijing |
| 1 | Bob | Shanghai |
| 2 | Cindy | Guangzhou |
🧩 示例 3:对象(键值对)
let scores = {
Alice: 95,
Bob: 88,
Cindy: 91
};
console.table(scores);
输出:
| (index) | Value |
|---|---|
| Alice | 95 |
| Bob | 88 |
| Cindy | 91 |
🧩 示例 4:嵌套对象数组
let products = [
{ id: 1, name: "Laptop", price: 5999 },
{ id: 2, name: "Phone", price: 3999 },
{ id: 3, name: "Tablet", price: 2999 }
];
console.table(products);
输出效果与表格类似,更方便阅读调试。
✅ 小结
| 功能 | 说明 |
|---|---|
| ✅ 输出表格形式 | 更直观地展示数组或对象内容 |
| ✅ 可选显示字段 | 可通过第二个参数过滤字段 |
| ✅ 调试利器 | 调试时比 console.log() 更高效 |
💡 适用于调试数组、对象、API 返回结果、数据结构等场景。

浙公网安备 33010602011771号