标准库
# 标准库
# 目录介绍
# 6.1 复合数据类型
# 6.1.1 Object
Object:JavaScript 中最基础的复合数据类型,用于存储键值对集合。
Object 的底层存储原理:V8 引擎对 Object 属性有两种存储策略。命名属性(Named Properties)存储在对象的属性存储区中,通过隐藏类(Hidden Class)定义结构;索引属性(Indexed Properties,如数字键)存储在元素存储区中,类似数组。当属性过多或动态增删频繁时,V8 会将属性存储从快速模式(线性存储)降级为字典模式(哈希表存储)。
常用静态方法:
const person = { name: "Alice", age: 25, city: "Beijing" };
// Object.keys():返回自身可枚举属性名数组
console.log(Object.keys(person)); // ["name", "age", "city"]
// Object.values():返回自身可枚举属性值数组
console.log(Object.values(person)); // ["Alice", 25, "Beijing"]
// Object.entries():返回 [key, value] 对数组
console.log(Object.entries(person));
// [["name", "Alice"], ["age", 25], ["city", "Beijing"]]
// Object.assign():浅拷贝合并对象
const defaults = { theme: "light", lang: "en" };
const userPrefs = { theme: "dark" };
const config = Object.assign({}, defaults, userPrefs);
console.log(config); // { theme: "dark", lang: "en" }
// Object.freeze():冻结对象,不可修改
const frozen = Object.freeze({ x: 1, y: 2 });
frozen.x = 100; // 静默失败(严格模式下报错)
console.log(frozen.x); // 1
// Object.fromEntries():从键值对数组创建对象(ES2019)
const map = new Map([["name", "Bob"], ["age", 30]]);
const obj = Object.fromEntries(map);
console.log(obj); // { name: "Bob", age: 30 }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
属性描述符:
const obj = {};
Object.defineProperty(obj, 'name', {
value: 'Alice',
writable: false, // 不可修改
enumerable: true, // 可枚举
configurable: false // 不可删除/重新配置
});
obj.name = 'Bob'; // 静默失败
console.log(obj.name); // "Alice"
2
3
4
5
6
7
8
9
10
# 6.1.2 Array
Array:创建和操作有序集合。
Array 的底层原理:V8 引擎中的数组并非简单的连续内存。当数组元素类型一致(如全是整数)时,V8 使用快速模式(Fast Elements),以 C++ 数组方式存储,访问效率接近 O(1);当数组包含不同类型元素、存在空洞(hole)或非常稀疏时,V8 切换为字典模式(Dictionary Elements),以哈希表存储,节省空间但访问变慢。
常用方法详解:
const arr = [1, 2, 3, 4, 5];
// ========= 变异方法(修改原数组)=========
arr.push(6); // 末尾添加,返回新长度 → [1,2,3,4,5,6]
arr.pop(); // 末尾删除,返回被删元素 → [1,2,3,4,5]
arr.unshift(0); // 开头添加 → [0,1,2,3,4,5]
arr.shift(); // 开头删除 → [1,2,3,4,5]
arr.splice(2, 1, 99); // 从索引2删除1个,插入99 → [1,2,99,4,5]
arr.sort((a, b) => a - b); // 原地排序
arr.reverse(); // 原地反转
// ========= 非变异方法(返回新数组)=========
const nums = [1, 2, 3, 4, 5];
// map:映射转换
const doubled = nums.map(n => n * 2); // [2, 4, 6, 8, 10]
// filter:过滤
const evens = nums.filter(n => n % 2 === 0); // [2, 4]
// reduce:归约
const sum = nums.reduce((acc, n) => acc + n, 0); // 15
// find / findIndex:查找
const found = nums.find(n => n > 3); // 4
const index = nums.findIndex(n => n > 3); // 3
// flat / flatMap(ES2019)
const nested = [1, [2, 3], [4, [5]]];
nested.flat(); // [1, 2, 3, 4, [5]]
nested.flat(2); // [1, 2, 3, 4, 5](指定深度)
nested.flat(Infinity); // [1, 2, 3, 4, 5]
// Array.from:从可迭代对象创建数组
Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']
Array.from({length: 5}, (_, i) => i); // [0, 1, 2, 3, 4]
// at()(ES2022):支持负索引
[1, 2, 3].at(-1); // 3
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
时间复杂度总结:
| 方法 | 时间复杂度 | 说明 |
|---|---|---|
push/pop | O(1) | 末尾操作 |
shift/unshift | O(n) | 需移动元素 |
splice | O(n) | 需移动元素 |
indexOf/find | O(n) | 线性查找 |
sort | O(n log n) | TimSort 算法 |
map/filter/reduce | O(n) | 遍历所有元素 |
# 6.1.3 Map
Map:存储键值对的集合,键可以是任意类型(包括对象、函数、NaN)。
Map 与 Object 的核心区别:
const map = new Map();
// 任意类型的键
map.set('string', 'value1');
map.set(42, 'value2');
map.set(true, 'value3');
const objKey = { id: 1 };
map.set(objKey, 'value4');
console.log(map.get(objKey)); // "value4"
console.log(map.size); // 4
// 遍历(保证插入顺序)
for (const [key, value] of map) {
console.log(key, value);
}
// 链式调用
new Map()
.set('a', 1)
.set('b', 2)
.set('c', 3);
// Map 与 Object 互转
const obj = Object.fromEntries(map); // Map → Object(键会被转为字符串)
const map2 = new Map(Object.entries(obj)); // Object → Map
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| 特性 | Object | Map |
|---|---|---|
| 键类型 | 仅 String/Symbol | 任意类型 |
| 键顺序 | 不保证(整数键排前面) | 保证插入顺序 |
| 大小 | Object.keys(o).length | map.size |
| 迭代 | 不可直接迭代 | 可直接 for...of |
| 性能 | 频繁增删较慢 | 频繁增删更优 |
| 原型键 | 有(toString 等) | 无 |
# 6.1.4 Set
Set:存储唯一值的集合(自动去重)。
const set = new Set([1, 2, 3, 3, 2, 1]);
console.log(set); // Set {1, 2, 3}
console.log(set.size); // 3
set.add(4);
set.delete(1);
console.log(set.has(2)); // true
// 数组去重的最简写法
const unique = [...new Set([1, 1, 2, 3, 3])]; // [1, 2, 3]
// 集合运算(ES2025 提案,部分引擎已支持)
const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);
// 交集
const intersection = new Set([...a].filter(x => b.has(x))); // {2, 3}
// 并集
const union = new Set([...a, ...b]); // {1, 2, 3, 4}
// 差集
const diff = new Set([...a].filter(x => !b.has(x))); // {1}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Set 判断唯一性的算法:Set 内部使用类似 === 的比较,但特殊处理了 NaN——在 Set 中 NaN 等于 NaN:
const set = new Set();
set.add(NaN);
set.add(NaN); // 不会重复添加
console.log(set.size); // 1
console.log(set.has(NaN)); // true
2
3
4
5
# 6.1.5 WeakMap和WeakSet
WeakMap 和 WeakSet:弱引用版本的 Map 和 Set。
弱引用的核心概念:WeakMap/WeakSet 中的键(WeakMap)或值(WeakSet)是弱引用——不会阻止垃圾回收。如果一个对象只被 WeakMap 引用,GC 可以回收它。
// WeakMap 典型应用:存储私有数据
const privateData = new WeakMap();
class Person {
constructor(name, secret) {
privateData.set(this, { secret });
this.name = name;
}
getSecret() {
return privateData.get(this).secret;
}
}
let person = new Person("Alice", "my-password");
console.log(person.getSecret()); // "my-password"
person = null; // person 被回收后,WeakMap 中对应的条目也会被自动清理
// WeakMap 典型应用:DOM 节点关联数据
const nodeData = new WeakMap();
const element = document.createElement('div');
nodeData.set(element, { clickCount: 0 });
// 当 element 从 DOM 移除并失去所有引用时,关联数据自动清理
// WeakSet 典型应用:标记已处理的对象
const processed = new WeakSet();
function processOnce(obj) {
if (processed.has(obj)) return;
processed.add(obj);
console.log('Processing:', obj);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
WeakMap/WeakSet 的限制:
- 键只能是对象(不能是原始类型)
- 不可迭代(没有
size、forEach、keys等方法) - 不可清空(没有
clear方法)
# 6.2 特殊数据类型
# 6.2.1 Date
Date:处理日期和时间。JavaScript 的 Date 对象基于 Unix 时间戳(1970年1月1日 UTC 起的毫秒数)。
// 创建方式
const now = new Date(); // 当前时间
const specific = new Date(2024, 0, 15); // 2024年1月15日(月份从0开始!)
const fromString = new Date('2024-01-15'); // ISO 格式字符串
const fromTimestamp = new Date(1705276800000); // 时间戳
// 常用方法
console.log(now.getFullYear()); // 2024
console.log(now.getMonth()); // 0-11(注意:0 = 一月)
console.log(now.getDate()); // 1-31
console.log(now.getDay()); // 0-6(0 = 星期日)
console.log(now.getTime()); // 时间戳(毫秒)
// 时间计算
const future = new Date();
future.setDate(future.getDate() + 7); // 7天后
// 时间差
const start = new Date('2024-01-01');
const end = new Date('2024-12-31');
const diffMs = end - start; // 毫秒差
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); // 365
// 高精度计时
const t0 = performance.now(); // 比 Date.now() 精度更高
// ... 执行代码 ...
const t1 = performance.now();
console.log(`耗时: ${t1 - t0}ms`);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Date 的陷阱:月份从 0 开始(0=一月),new Date(2024, 1, 15) 是2月15日而非1月15日。
# 6.2.2 RegExp
RegExp:处理正则表达式,用于模式匹配和文本替换。
正则表达式的底层原理:JavaScript 正则引擎使用**回溯法(Backtracking)的 NFA(非确定性有限自动机)实现。V8 中有两套正则引擎:Irregexp(解释执行)和 JIT 编译版本(对热点正则进行编译优化)。理解回溯行为对避免灾难性回溯(Catastrophic Backtracking)**非常重要。
// 创建方式
const re1 = /hello/gi; // 字面量(推荐)
const re2 = new RegExp('hello', 'gi'); // 构造函数
// 常用方法
const str = 'Hello World, hello JavaScript';
console.log(re1.test(str)); // true(是否匹配)
console.log(re1.exec(str)); // 匹配详情(含 index)
// 字符串方法配合正则
console.log(str.match(/hello/gi)); // ["Hello", "hello"]
console.log(str.replace(/hello/gi, 'Hi')); // "Hi World, Hi JavaScript"
console.log(str.search(/world/i)); // 6(首次匹配位置)
console.log(str.split(/,\s*/)); // ["Hello World", "hello JavaScript"]
// 命名捕获组(ES2018)
const dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2024-01-15'.match(dateRe);
console.log(match.groups.year); // "2024"
console.log(match.groups.month); // "01"
// matchAll(ES2020)—— 获取所有匹配
const text = 'cat bat hat';
for (const m of text.matchAll(/[a-z]at/g)) {
console.log(m[0], m.index); // "cat" 0, "bat" 4, "hat" 8
}
// 灾难性回溯的例子(避免这样写!)
// /^(a+)+$/.test('aaaaaaaaaaaaaaaaaaaab'); // 极慢!指数级回溯
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 6.2.3 Error
Error:处理错误对象,详见第9章错误机制。
// 内置错误类型
try {
undeclaredVar; // ReferenceError
} catch (e) {
console.log(e.name); // "ReferenceError"
console.log(e.message); // "undeclaredVar is not defined"
console.log(e.stack); // 完整堆栈信息
}
// 常见错误类型
// SyntaxError: 语法错误(解析时)
// TypeError: 类型错误(如调用非函数)
// RangeError: 范围错误(如数组长度为负)
// ReferenceError: 引用错误(如访问未声明的变量)
// URIError: URI 处理错误
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 6.3 全局对象
# 6.3.1 Math
Math:提供数学运算功能。Math 不是构造函数,所有方法都是静态的。
// 常用常量
Math.PI; // 3.141592653589793
Math.E; // 2.718281828459045
// 常用方法
Math.random(); // [0, 1) 随机数
Math.floor(4.7); // 4(向下取整)
Math.ceil(4.2); // 5(向上取整)
Math.round(4.5); // 5(四舍五入)
Math.trunc(4.9); // 4(截断小数部分)
Math.max(1, 5, 3); // 5
Math.min(1, 5, 3); // 1
Math.abs(-5); // 5
Math.pow(2, 10); // 1024
Math.sqrt(16); // 4
Math.log2(8); // 3
// 生成指定范围的随机整数
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(randomInt(1, 100)); // 1-100 之间的随机整数
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 6.3.2 JSON
JSON:处理 JSON 数据的序列化和反序列化。
JSON 的设计原理:JSON(JavaScript Object Notation)由 Douglas Crockford 在 2001 年提出,它是 JavaScript 对象字面量语法的一个严格子集。JSON 之所以成为 Web 数据交换的事实标准,是因为它足够简单、自描述、语言无关。
const data = {
name: "Alice",
age: 25,
hobbies: ["reading", "coding"],
address: { city: "Beijing" }
};
// 序列化
const json = JSON.stringify(data);
console.log(json);
// '{"name":"Alice","age":25,"hobbies":["reading","coding"],"address":{"city":"Beijing"}}'
// 格式化输出
console.log(JSON.stringify(data, null, 2)); // 2空格缩进
// replacer 函数:自定义序列化
const filtered = JSON.stringify(data, (key, value) => {
if (key === 'age') return undefined; // 排除 age
return value;
});
// 反序列化
const parsed = JSON.parse(json);
// reviver 函数:自定义反序列化
const withDate = '{"date":"2024-01-15T00:00:00.000Z"}';
const obj = JSON.parse(withDate, (key, value) => {
if (key === 'date') return new Date(value);
return value;
});
// JSON.stringify 不能序列化的值
JSON.stringify(undefined); // undefined(被忽略)
JSON.stringify(function(){}); // undefined
JSON.stringify(Symbol()); // undefined
JSON.stringify(NaN); // "null"
JSON.stringify(Infinity); // "null"
// 循环引用会抛出 TypeError
// toJSON 方法:自定义序列化行为
class User {
constructor(name, password) {
this.name = name;
this.password = password;
}
toJSON() {
return { name: this.name }; // 序列化时排除密码
}
}
console.log(JSON.stringify(new User("Alice", "123"))); // {"name":"Alice"}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 6.3.3 Promise
Promise:处理异步操作(详见第7章异步操作)。
// 快捷创建
const resolved = Promise.resolve(42);
const rejected = Promise.reject(new Error('fail'));
// 静态方法
Promise.all([p1, p2, p3]); // 全部成功才成功
Promise.allSettled([p1, p2, p3]); // 等待全部完成(无论成败)
Promise.race([p1, p2, p3]); // 取最先完成的
Promise.any([p1, p2, p3]); // 取最先成功的(ES2021)
2
3
4
5
6
7
8
9
# 6.3.4 Proxy
Proxy:创建对象的代理,拦截对象的基本操作。
Proxy 的设计原理:Proxy 是 ES6 引入的元编程(Metaprogramming)特性,它基于 ECMAScript 规范定义的内部方法(Internal Methods)。每个 JavaScript 对象都有 [[Get]]、[[Set]]、[[Delete]] 等内部方法,Proxy 允许你拦截并自定义这些方法的行为。Vue 3 的响应式系统就是基于 Proxy 实现的。
// 基础用法
const handler = {
get(target, prop, receiver) {
console.log(`读取属性: ${prop}`);
return Reflect.get(target, prop, receiver);
},
set(target, prop, value, receiver) {
console.log(`设置属性: ${prop} = ${value}`);
return Reflect.set(target, prop, value, receiver);
}
};
const person = new Proxy({ name: "Alice" }, handler);
person.name; // 读取属性: name → "Alice"
person.age = 25; // 设置属性: age = 25
// 实际应用:数据验证
function createValidated(schema) {
return new Proxy({}, {
set(target, prop, value) {
const validator = schema[prop];
if (validator && !validator(value)) {
throw new TypeError(`Invalid value for ${prop}: ${value}`);
}
target[prop] = value;
return true;
}
});
}
const user = createValidated({
name: v => typeof v === 'string' && v.length > 0,
age: v => typeof v === 'number' && v >= 0 && v <= 150,
email: v => /^\S+@\S+\.\S+$/.test(v)
});
user.name = "Alice"; // OK
user.age = 25; // OK
// user.age = -1; // TypeError: Invalid value for age: -1
// 实际应用:负索引数组
function createNegativeArray(arr) {
return new Proxy(arr, {
get(target, prop) {
const index = Number(prop);
if (index < 0) {
return target[target.length + index];
}
return target[prop];
}
});
}
const arr = createNegativeArray([1, 2, 3, 4, 5]);
console.log(arr[-1]); // 5
console.log(arr[-2]); // 4
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# 6.3.5 Reflect
Reflect:提供操作对象的静态方法,与 Proxy 的 handler 方法一一对应。
const obj = { x: 1, y: 2 };
// Reflect 方法与旧语法的对应关系
Reflect.get(obj, 'x'); // 等价于 obj.x
Reflect.set(obj, 'z', 3); // 等价于 obj.z = 3
Reflect.has(obj, 'x'); // 等价于 'x' in obj
Reflect.deleteProperty(obj, 'x'); // 等价于 delete obj.x
Reflect.ownKeys(obj); // 返回所有自身属性(包括 Symbol)
// Reflect 的优势:返回布尔值表示操作是否成功,而不是抛出异常
const frozen = Object.freeze({ a: 1 });
console.log(Reflect.set(frozen, 'a', 2)); // false(而 frozen.a = 2 静默失败)
2
3
4
5
6
7
8
9
10
11
12
# 6.4 全局函数
# 6.4.1 eval
eval():执行字符串中的 JavaScript 代码。
eval('2 + 2'); // 4
eval('console.log("Hello")'); // 输出 Hello
2
安全警告:eval 存在严重的安全风险和性能问题:
- 安全风险:可以执行任意代码,容易被注入攻击
- 性能问题:使用 eval 会导致 V8 无法优化当前作用域(因为无法预知 eval 会访问/修改哪些变量)
- 调试困难:eval 中的代码不会出现在正常的调用栈中
替代方案:JSON.parse() 解析 JSON,Function() 构造函数创建函数,new Map() 代替动态属性名。
# 6.4.2 isNaN
isNaN() 和 Number.isNaN():检查值是否为 NaN。
// 全局 isNaN(有类型转换,容易误判)
isNaN(NaN); // true
isNaN("hello"); // true("hello" 转为 NaN)
isNaN(undefined); // true(undefined 转为 NaN)
// Number.isNaN(严格判断,推荐使用)
Number.isNaN(NaN); // true
Number.isNaN("hello"); // false
Number.isNaN(undefined); // false
2
3
4
5
6
7
8
9
# 6.4.3 isFinite
isFinite():检查值是否为有限数。
isFinite(42); // true
isFinite(Infinity); // false
isFinite(NaN); // false
// Number.isFinite 更严格(不做类型转换)
Number.isFinite("42"); // false
isFinite("42"); // true("42" 转为 42)
2
3
4
5
6
7
# 6.4.4 parseInt
parseInt() 和 parseFloat():将字符串转换为整数或浮点数。
parseInt('42'); // 42
parseInt('42px'); // 42(解析到非数字字符为止)
parseInt('0xFF', 16); // 255(指定基数)
parseInt('111', 2); // 7(二进制)
parseFloat('3.14'); // 3.14
parseFloat('3.14.15'); // 3.14(只解析第一个小数点)
// 常见陷阱
parseInt('08'); // 8(曾经在旧引擎中为 0,因为被当作八进制)
parseInt(0.0000005); // 5!(0.0000005 先转为 "5e-7",parseInt 解析 "5")
2
3
4
5
6
7
8
9
10
11
# 6.4.5 encodeURI
encodeURI() 和 decodeURI():编码/解码完整 URI,保留 URI 结构字符(/、?、#、& 等)。
const uri = 'https://example.com/路径?name=张三&age=25';
const encoded = encodeURI(uri);
console.log(encoded);
// "https://example.com/%E8%B7%AF%E5%BE%84?name=%E5%BC%A0%E4%B8%89&age=25"
console.log(decodeURI(encoded)); // 还原
2
3
4
5
# 6.4.6 encodeURIComponent
encodeURIComponent() 和 decodeURIComponent():编码/解码 URI 组件,会编码所有特殊字符(包括 /、?、& 等)。
const param = 'name=张三&city=北京';
const encoded = encodeURIComponent(param);
console.log(encoded);
// "name%3D%E5%BC%A0%E4%B8%89%26city%3D%E5%8C%97%E4%BA%AC"
// 典型使用场景:构建查询参数
const url = `https://api.example.com/search?q=${encodeURIComponent('hello world&more')}`;
2
3
4
5
6
7
encodeURI vs encodeURIComponent:
encodeURI:编码整个 URL,保留://、/、?、#、&等encodeURIComponent:编码参数值,会编码上述所有字符
# 6.5 浏览器相关
# 6.5.1 Window
- 表示浏览器窗口,是浏览器环境中的全局对象。
- 属性:
window.document、window.location、window.localStorage。 - 所有全局变量和函数都是
window的属性。
// window 就是全局对象
var x = 1;
console.log(window.x); // 1
// 常用属性
console.log(window.innerWidth); // 视口宽度
console.log(window.innerHeight); // 视口高度
console.log(window.devicePixelRatio); // 设备像素比
// 常用方法
window.alert('Hello');
window.confirm('确定?'); // 返回 boolean
window.prompt('请输入:'); // 返回字符串或 null
// 定时器(实际上是 window 的方法)
window.setTimeout(() => {}, 1000);
window.setInterval(() => {}, 1000);
window.requestAnimationFrame(() => {}); // 动画首选
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 6.5.2 Document
- 表示 HTML 文档,是 DOM 树的根节点。
// 查找元素
document.getElementById('app');
document.querySelector('.class');
document.querySelectorAll('div');
// 创建元素
const div = document.createElement('div');
div.textContent = 'Hello';
div.className = 'my-class';
document.body.appendChild(div);
// DOM 操作性能优化:使用 DocumentFragment
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const li = document.createElement('li');
li.textContent = `Item ${i}`;
fragment.appendChild(li); // 不触发重排
}
document.getElementById('list').appendChild(fragment); // 一次性插入
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 6.5.3 Navigator
- 提供浏览器信息。
console.log(navigator.userAgent); // 浏览器标识
console.log(navigator.language); // 语言
console.log(navigator.onLine); // 是否在线
console.log(navigator.hardwareConcurrency); // CPU 核心数
// 现代 API
navigator.clipboard.writeText('复制内容'); // 复制到剪贴板
navigator.geolocation.getCurrentPosition(pos => {
console.log(pos.coords.latitude, pos.coords.longitude);
});
2
3
4
5
6
7
8
9
10
# 6.5.4 Location
- 提供当前页面的 URL 信息和导航控制。
// URL 解析
console.log(location.href); // 完整 URL
console.log(location.protocol); // "https:"
console.log(location.host); // "example.com:8080"
console.log(location.hostname); // "example.com"
console.log(location.port); // "8080"
console.log(location.pathname); // "/path/to/page"
console.log(location.search); // "?key=value"
console.log(location.hash); // "#section"
// 导航
location.href = 'https://example.com'; // 跳转(有历史记录)
location.replace('https://example.com'); // 替换(无历史记录)
location.reload(); // 刷新
// URLSearchParams(现代 API)
const params = new URLSearchParams(location.search);
params.get('key');
params.set('key', 'newValue');
params.append('key2', 'value2');
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 6.5.5 History
- 提供浏览器历史记录操作,SPA 路由的基础。
history.back(); // 后退
history.forward(); // 前进
history.go(-2); // 后退2页
// pushState / replaceState(SPA 核心)
history.pushState({ page: 1 }, 'title', '/page1'); // 添加历史记录
history.replaceState({ page: 2 }, 'title', '/page2'); // 替换当前记录
// 监听历史变化
window.addEventListener('popstate', (event) => {
console.log('导航到:', location.pathname, event.state);
});
2
3
4
5
6
7
8
9
10
11
12
# 6.5.6 Storage
提供本地存储功能,数据持久化在浏览器中。
// localStorage:永久存储(除非手动清除)
localStorage.setItem('user', JSON.stringify({ name: 'Alice' }));
const user = JSON.parse(localStorage.getItem('user'));
localStorage.removeItem('user');
localStorage.clear(); // 清除所有
// sessionStorage:会话存储(关闭标签页即清除)
sessionStorage.setItem('token', 'abc123');
// 限制:通常 5-10MB,只能存储字符串
// 监听存储变化(跨标签页通信)
window.addEventListener('storage', (event) => {
console.log('存储变化:', event.key, event.oldValue, event.newValue);
});
2
3
4
5
6
7
8
9
10
11
12
13
14
# 6.5.7 Fetch
Fetch API 是现代的网络请求 API,替代 XMLHttpRequest。
// GET 请求
const response = await fetch('https://api.example.com/users');
const data = await response.json();
// POST 请求
const result = await fetch('https://api.example.com/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Alice' })
});
// 注意:fetch 不会在 HTTP 错误状态(404、500)时 reject
// 需要手动检查 response.ok
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
// 超时控制(使用 AbortController)
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000); // 5秒超时
try {
const res = await fetch(url, { signal: controller.signal });
} catch (err) {
if (err.name === 'AbortError') console.log('请求超时');
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 6.5.8 WebSocket
用于实现全双工实时通信。
const ws = new WebSocket('wss://example.com/socket');
ws.onopen = () => {
console.log('连接已建立');
ws.send(JSON.stringify({ type: 'hello' }));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('收到消息:', data);
};
ws.onerror = (error) => console.error('WebSocket 错误:', error);
ws.onclose = () => console.log('连接已关闭');
// 关闭连接
ws.close(1000, '正常关闭');
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 6.6 国际化与本地化
# 6.6.1 Intl
- 提供国际化功能,支持日期、数字、货币等的本地化格式。
// 数字格式化
const numFmt = new Intl.NumberFormat('zh-CN', {
style: 'currency',
currency: 'CNY'
});
console.log(numFmt.format(1234567.89)); // "¥1,234,567.89"
// 日期格式化
const dateFmt = new Intl.DateTimeFormat('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long'
});
console.log(dateFmt.format(new Date())); // "2024年1月15日星期一"
// 相对时间(ES2020)
const rtf = new Intl.RelativeTimeFormat('zh-CN', { numeric: 'auto' });
console.log(rtf.format(-1, 'day')); // "昨天"
console.log(rtf.format(2, 'hour')); // "后天"
console.log(rtf.format(-3, 'month')); // "3个月前"
// 列表格式化
const listFmt = new Intl.ListFormat('zh-CN', { type: 'conjunction' });
console.log(listFmt.format(['苹果', '香蕉', '橘子'])); // "苹果、香蕉和橘子"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 6.6.2 toLocaleString
- 根据本地化规则格式化数据。
// 数字
(1234567.89).toLocaleString('zh-CN'); // "1,234,567.89"
(0.75).toLocaleString('zh-CN', { style: 'percent' }); // "75%"
// 日期
new Date().toLocaleString('zh-CN'); // "2024/1/15 14:30:00"
new Date().toLocaleDateString('zh-CN'); // "2024/1/15"
new Date().toLocaleTimeString('zh-CN'); // "14:30:00"
2
3
4
5
6
7
8
# 6.7 二进制与文件
# 6.7.1 ArrayBuffer
表示通用的二进制数据缓冲区,不能直接操作,需要通过**视图(TypedArray 或 DataView)**访问。
// 创建 8 字节缓冲区
const buffer = new ArrayBuffer(8);
// 通过 TypedArray 操作
const int32View = new Int32Array(buffer);
int32View[0] = 42;
int32View[1] = 99;
console.log(int32View); // Int32Array [42, 99]
// 通过 DataView 操作(可指定字节序)
const view = new DataView(buffer);
view.setFloat64(0, 3.14);
console.log(view.getFloat64(0)); // 3.14
2
3
4
5
6
7
8
9
10
11
12
13
# 6.7.2 Blob
表示不可变的二进制数据对象,通常用于文件操作。
// 创建 Blob
const blob = new Blob(['Hello, World!'], { type: 'text/plain' });
console.log(blob.size); // 13
console.log(blob.type); // "text/plain"
// 生成下载链接
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'hello.txt';
a.click();
URL.revokeObjectURL(url); // 释放内存
2
3
4
5
6
7
8
9
10
11
12
# 6.7.3 File
表示文件对象,继承自 Blob,通常来自 <input type="file"> 或拖放操作。
document.querySelector('input[type="file"]').addEventListener('change', (e) => {
const file = e.target.files[0];
console.log(file.name); // 文件名
console.log(file.size); // 大小(字节)
console.log(file.type); // MIME 类型
console.log(file.lastModified); // 最后修改时间戳
});
2
3
4
5
6
7
# 6.7.4 FileReader
读取文件内容。
const reader = new FileReader();
reader.onload = (e) => {
console.log(e.target.result); // 文件内容
};
reader.onerror = (e) => {
console.error('读取失败:', e);
};
// 不同的读取方式
reader.readAsText(file); // 读取为文本
reader.readAsDataURL(file); // 读取为 Base64 Data URL
reader.readAsArrayBuffer(file); // 读取为 ArrayBuffer
2
3
4
5
6
7
8
9
10
11
12
13
14