目标:掌握 JavaScript 中的各种数据结构(数组、Map、Set、TypedArray)和 JSON 处理,理解它们的特性、使用场景和最佳实践。
目录
集合类型总览
JSON:数据交换格式
其他内置对象
实战应用场景
代码片段速查
常见问题与解决方案
速记与总结
1. 集合类型总览 1.1 数组(Array)与类数组 数组是 JavaScript 中最常用的数据结构之一,用于存储有序的元素集合。
1.1.1 数组的核心特性 1. 有序集合,索引从 0 开始
1 2 3 4 const arr = ['a' , 'b' , 'c' ];console .log (arr[0 ]); console .log (arr[1 ]); console .log (arr[2 ]);
2. length 属性可读写
1 2 3 4 5 6 7 8 9 10 11 12 const arr = [1 , 2 , 3 ];console .log (arr.length ); arr.length = 5 ; console .log (arr); console .log (arr[3 ]); arr.length = 2 ; console .log (arr); console .log (arr[2 ]);
3. 稀疏数组(Sparse Array)
稀疏数组是指中间有空缺元素的数组。
1 2 3 4 5 6 7 8 9 10 11 const sparse = new Array (5 );console .log (sparse); const sparse2 = [1 , , , 4 ];console .log (sparse2); console .log (1 in sparse2); console .log (0 in sparse2);
稀疏数组的特殊行为 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const sparse = [1 , , , 4 ];sparse.forEach ((item, index ) => { console .log (index, item); }); const mapped = sparse.map (x => x * 2 );console .log (mapped); const filtered = sparse.filter (x => true );console .log (filtered);
1.1.2 数组的创建方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const arr1 = [1 , 2 , 3 ];const arr2 = new Array (3 ); const arr3 = new Array (1 , 2 , 3 ); const arr4 = Array .of (3 ); const arr5 = Array .of (1 , 2 , 3 ); const arr6 = Array .from ('abc' ); const arr7 = Array .from ([1 , 2 , 3 ], x => x * 2 ); const arr8 = Array .from ({ length : 3 }, (_, i ) => i); const arr9 = [...'abc' ];
Array.of vs new Array :
1 2 3 4 5 6 7 new Array (3 ); new Array (1 , 2 , 3 ); Array .of (3 ); Array .of (1 , 2 , 3 );
1.1.3 常用数组方法详解 不改变原数组的方法(返回新数组) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 const arr = [1 , 2 , 3 , 4 , 5 ];const doubled = arr.map (x => x * 2 );console .log (doubled); console .log (arr); const evens = arr.filter (x => x % 2 === 0 );console .log (evens); const slice1 = arr.slice (1 , 3 ); const slice2 = arr.slice (2 ); const slice3 = arr.slice (-2 ); const concat = arr.concat ([6 , 7 ]);console .log (concat); const sorted = arr.toSorted ((a, b ) => b - a); const reversed = arr.toReversed (); const spliced = arr.toSpliced (1 , 2 , 99 , 100 );
改变原数组的方法 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 const arr = [1 , 2 , 3 ];arr.push (4 ); console .log (arr); const last = arr.pop ();console .log (last); console .log (arr); const first = arr.shift ();console .log (first); console .log (arr); arr.unshift (0 ); console .log (arr); arr.splice (1 , 1 , 99 ); console .log (arr); arr.reverse (); console .log (arr); arr.sort ((a, b ) => a - b); console .log (arr);
查找与判断方法 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const arr = [1 , 2 , 3 , 2 , 4 ];console .log (arr.indexOf (2 )); console .log (arr.lastIndexOf (2 )); console .log (arr.includes (3 )); console .log (arr.includes (5 )); const found = arr.find (x => x > 2 );console .log (found); const index = arr.findIndex (x => x > 2 );console .log (index); const lastFound = arr.findLast (x => x > 2 );console .log (lastFound);
其他常用方法 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 const arr = [1 , 2 , 3 , 4 , 5 ];arr.forEach ((item, index ) => { console .log (index, item); }); const sum = arr.reduce ((acc, val ) => acc + val, 0 );console .log (sum); const hasEven = arr.some (x => x % 2 === 0 );console .log (hasEven); const allPositive = arr.every (x => x > 0 );console .log (allPositive); const nested = [1 , [2 , 3 ], [4 , [5 ]]];console .log (nested.flat ()); console .log (nested.flat (2 )); console .log (nested.flat (Infinity )); const doubled = arr.flatMap (x => [x, x * 2 ]);console .log (doubled);
1.1.4 类数组(Array-like) 类数组对象具有数组的特征(数值索引、length 属性),但不是真正的数组。
常见的类数组对象 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function test ( ) { console .log (arguments ); console .log (Array .isArray (arguments )); console .log (arguments .length ); console .log (arguments [0 ]); } test (1 , 2 , 3 );const nodes = document .querySelectorAll ('div' );console .log (nodes); console .log (Array .isArray (nodes)); const elements = document .getElementsByTagName ('div' );console .log (elements); console .log (Array .isArray (elements)); const arrayLike = { 0 : 'a' , 1 : 'b' , 2 : 'c' , length : 3 };
类数组转换为数组 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function test ( ) { const arr1 = Array .from (arguments ); console .log (Array .isArray (arr1)); } function test ( ) { const arr2 = [...arguments ]; console .log (Array .isArray (arr2)); } function test ( ) { const arr3 = Array .prototype .slice .call (arguments ); console .log (Array .isArray (arr3)); } function test ( ) { const doubled = Array .prototype .map .call (arguments , x => x * 2 ); console .log (doubled); }
常见坑 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function test ( ) { arguments .map (x => x * 2 ); } function test ( ) { const arr = Array .from (arguments ); arr.map (x => x * 2 ); } function test ( ) { Array .prototype .map .call (arguments , x => x * 2 ); }
1.2 Map 与 WeakMap 1.2.1 Map:键值对集合 Map 是 ES6 引入的键值对数据结构,与 Object 相比有以下优势:
1. 键可以是任意类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const map = new Map ();map.set ('name' , 'Alice' ); map.set (123 , '数字键' ); const objKey = { id : 1 };map.set (objKey, '对象键的值' ); const fnKey = ( ) => {};map.set (fnKey, '函数键的值' ); console .log (map.get ('name' )); console .log (map.get (123 )); console .log (map.get (objKey)); console .log (map.get (fnKey));
Object vs Map 的键 :
1 2 3 4 5 6 7 8 9 10 11 12 const obj = {};obj[1 ] = 'one' ; obj['1' ] = 'one string' ; console .log (obj); const map = new Map ();map.set (1 , 'one' ); map.set ('1' , 'one string' ); console .log (map.get (1 )); console .log (map.get ('1' ));
2. 保持插入顺序
1 2 3 4 5 6 7 8 9 10 11 12 13 const map = new Map ();map.set ('first' , 1 ); map.set ('second' , 2 ); map.set ('third' , 3 ); for (const [key, value] of map) { console .log (key, value); }
3. 常用 API :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 const map = new Map ();map.set ('name' , 'Alice' ); map.set ('age' , 25 ); console .log (map.get ('name' )); console .log (map.get ('unknown' )); console .log (map.has ('name' )); console .log (map.has ('unknown' )); map.delete ('age' ); console .log (map.has ('age' )); console .log (map.size ); map.clear (); console .log (map.size ); map.set ('a' , 1 ); map.set ('b' , 2 ); for (const [key, value] of map) { console .log (key, value); } map.forEach ((value, key ) => { console .log (key, value); }); console .log ([...map.keys ()]); console .log ([...map.values ()]); console .log ([...map.entries ()]);
4. Map 的创建 :
1 2 3 4 5 6 7 8 9 10 11 12 const map1 = new Map ();const map2 = new Map ([ ['name' , 'Alice' ], ['age' , 25 ] ]); const obj = { name : 'Alice' , age : 25 };const map3 = new Map (Object .entries (obj));
5. 适用场景 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const userMetadata = new Map ();const user1 = { id : 1 };const user2 = { id : 2 };userMetadata.set (user1, { lastLogin : new Date () }); userMetadata.set (user2, { lastLogin : new Date () }); const orderedMap = new Map ();orderedMap.set ('first' , 1 ); orderedMap.set ('second' , 2 );
1.2.2 WeakMap:弱引用的 Map WeakMap 与 Map 的区别:
键必须是对象 (不能是原始值)
弱引用 :如果键对象没有其他引用,会被垃圾回收
不可遍历 :没有 keys、values、entries、forEach、size
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const wm = new WeakMap ();const obj = {};wm.set (obj, 'value' ); wm.set ('string' , 'value' ); console .log (wm.get (obj)); console .log (wm.has (obj)); wm.delete (obj);
弱引用的意义 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const elementData = new WeakMap ();function attachData (element, data ) { elementData.set (element, data); } function getData (element ) { return elementData.get (element); } const div = document .createElement ('div' );attachData (div, { clicked : 0 , hovered : false });
WeakMap vs Map :
1 2 3 4 5 6 7 8 9 10 11 const map = new Map ();let obj = { data : 'large' };map.set (obj, 'metadata' ); obj = null ; const wm = new WeakMap ();let obj2 = { data : 'large' };wm.set (obj2, 'metadata' ); obj2 = null ;
典型用途 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 const privateData = new WeakMap ();class User { constructor (name ) { privateData.set (this , { name }); } getName ( ) { return privateData.get (this ).name ; } } const cache = new WeakMap ();function expensiveOperation (obj ) { if (cache.has (obj)) { return cache.get (obj); } const result = ; cache.set (obj, result); return result; }
1.3 Set 与 WeakSet 1.3.1 Set:无重复值集合 Set 是 ES6 引入的集合数据结构,用于存储唯一值。
1. 自动去重
1 2 3 4 5 6 const set = new Set ([1 , 2 , 2 , 3 , 3 , 3 ]);console .log (set); set.add (2 ); console .log (set);
2. SameValueZero 比较
Set 使用 SameValueZero 算法比较值,类似于 ===,但对 NaN 友好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const set = new Set ();set.add (NaN ); set.add (NaN ); console .log (set.size ); const obj1 = {};const obj2 = {};set.add (obj1); set.add (obj2); console .log (set.size ); set.add (1 ); set.add ('1' ); console .log (set.size );
3. 常用 API :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 const set = new Set ([1 , 2 , 3 ]);set.add (4 ); console .log (set); console .log (set.has (2 )); console .log (set.has (5 )); set.delete (2 ); console .log (set.has (2 )); console .log (set.size ); set.clear (); console .log (set.size ); set.add (1 ); set.add (2 ); set.add (3 ); for (const value of set) { console .log (value); } set.forEach (value => { console .log (value); }); const arr = [...set];
4. Set 的创建 :
1 2 3 4 5 6 7 8 9 10 11 const set1 = new Set ();const set2 = new Set ([1 , 2 , 3 ]);const set3 = new Set ('abc' ); const set4 = new Set ([1 , 2 , 3 ].map (x => x * 2 ));
5. 典型用途 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 const arr = [1 , 2 , 2 , 3 , 3 , 3 ];const unique = [...new Set (arr)];console .log (unique); const visited = new Set ();function visit (id ) { if (visited.has (id)) { console .log ('已访问' ); return ; } visited.add (id); console .log ('首次访问' ); } const set1 = new Set ([1 , 2 , 3 ]);const set2 = new Set ([2 , 3 , 4 ]);const intersection = new Set ([...set1].filter (x => set2.has (x)));console .log ([...intersection]); const union = new Set ([...set1, ...set2]);console .log ([...union]); const difference = new Set ([...set1].filter (x => !set2.has (x)));console .log ([...difference]);
1.3.2 WeakSet:弱引用的 Set WeakSet 与 Set 的区别:
元素必须是对象
弱引用 :如果对象没有其他引用,会被垃圾回收
不可遍历 :没有 keys、values、forEach、size
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const ws = new WeakSet ();const obj = {};ws.add (obj); ws.add ('string' ); console .log (ws.has (obj)); ws.delete (obj);
典型用途 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const processed = new WeakSet ();function processObject (obj ) { if (processed.has (obj)) { console .log ('已处理,跳过' ); return ; } console .log ('处理对象' ); processed.add (obj); } const obj1 = { id : 1 };const obj2 = { id : 2 };processObject (obj1); processObject (obj1); processObject (obj2);
1.4 Typed Arrays(类型数组) Typed Arrays 是用于处理二进制数据的数组类型,提供高性能的数值运算能力。
1.4.1 什么是 Typed Arrays? Typed Arrays 是基于 ArrayBuffer 的视图,用于:
高性能数值运算
WebGL 图形处理
音视频处理
与 WebAssembly 交互
网络协议解析
1.4.2 ArrayBuffer ArrayBuffer 是一块原始二进制数据缓冲区。
1 2 3 4 5 6 const buffer = new ArrayBuffer (8 );console .log (buffer.byteLength );
1.4.3 TypedArray 视图 TypedArray 是 ArrayBuffer 的视图,提供了不同的数据类型和字节序。
常见的 TypedArray 类型 :
类型
字节数
值范围
Int8Array
1
-128 到 127
Uint8Array
1
0 到 255
Int16Array
2
-32768 到 32767
Uint16Array
2
0 到 65535
Int32Array
4
-2^31 到 2^31-1
Uint32Array
4
0 到 2^32-1
Float32Array
4
32位浮点数
Float64Array
8
64位浮点数
基本使用 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const buffer = new ArrayBuffer (16 ); const view8 = new Uint8Array (buffer); const view32 = new Uint32Array (buffer); view8[0 ] = 255 ; view8[1 ] = 16 ; view32[0 ] = 123456 ; console .log (view8[0 ]); console .log (view32[0 ]);
TypedArray 的特性 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const arr = new Int8Array (5 );console .log (arr.length ); arr[0 ] = 100 ; arr[1 ] = -50 ; const arr2 = new Int8Array (3 );console .log (arr2); const arr3 = new Int8Array ([1 , 2 , 3 ]);console .log (arr3); const normalArr = [1 , 2 , 3 ];const typedArr = new Int8Array (normalArr);console .log (typedArr);
实际应用示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 function processImageData (imageData ) { const data = new Uint8ClampedArray (imageData.data ); for (let i = 0 ; i < data.length ; i += 4 ) { const gray = (data[i] + data[i + 1 ] + data[i + 2 ]) / 3 ; data[i] = gray; data[i + 1 ] = gray; data[i + 2 ] = gray; } return data; } function calculateSum (numbers ) { const typedArray = new Float64Array (numbers); let sum = 0 ; for (let i = 0 ; i < typedArray.length ; i++) { sum += typedArray[i]; } return sum; } function serializeData (data ) { const buffer = new ArrayBuffer (data.length * 4 ); const view = new Float32Array (buffer); for (let i = 0 ; i < data.length ; i++) { view[i] = data[i]; } return buffer; }
2. JSON:数据交换格式 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,广泛用于前后端数据传输。
2.1 JSON 格式与语法 2.1.1 基本规则 JSON 基于 JavaScript 对象字面量,但更严格:
字符串必须用双引号 (不能用单引号)
键必须是双引号包裹的字符串
1 2 3 4 { "name" : "Alice" , "age" : 25 }
1 2 3 4 { name : "Alice" , age : 25 }
不允许尾随逗号
1 2 3 4 { "name" : "Alice" , "age" : 25 }
1 2 3 4 { "name" : "Alice" , "age" : 25 , }
不支持的类型 :
undefined
NaN
Infinity
函数
Symbol
Date(会被转换为字符串)
合法的 JSON 值类型 :
字符串(string)
数字(number)
布尔值(boolean)
null
对象(object)
数组(array)
示例合法 JSON :
1 2 3 4 5 6 7 8 9 10 { "name" : "Alice" , "age" : 25 , "isActive" : true , "hobbies" : [ "reading" , "game" ] , "profile" : { "online" : true , "lastLogin" : null } }
2.1.2 JSON vs JavaScript 对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const jsObj = { name : 'Alice' , age : 25 , undefined : undefined , fn : function ( ) {}, date : new Date (), symbol : Symbol ('test' ) }; const jsonStr = JSON .stringify (jsObj);console .log (jsonStr);
2.2 JSON.parse() 与 JSON.stringify() 2.2.1 JSON.parse(text, reviver?) JSON.parse 将 JSON 字符串解析为 JavaScript 值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const json = '{"name":"Alice","age":25}' ;const obj = JSON .parse (json);console .log (obj); const jsonArray = '[1,2,3]' ;const arr = JSON .parse (jsonArray);console .log (arr); const nestedJson = '{"user":{"name":"Alice"}}' ;const nested = JSON .parse (nestedJson);console .log (nested.user .name );
reviver 参数 :
reviver 是一个函数,用于在解析过程中转换值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const json = '{"age":"25","date":"2026-01-05"}' ;const obj = JSON .parse (json, (key, value ) => { if (key === 'age' ) { return Number (value); } if (key === 'date' ) { return new Date (value); } return value; }); console .log (obj.age ); console .log (obj.date );
reviver 的执行顺序 :
1 2 3 4 5 6 7 8 9 10 11 12 const json = '{"a":1,"b":{"c":2}}' ;JSON .parse (json, (key, value ) => { console .log (key, value); return value; });
错误处理 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 try { JSON .parse ('{name:"Alice"}' ); } catch (error) { console .error ('解析失败:' , error.message ); } function safeParse (json, defaultValue = null ) { try { return JSON .parse (json); } catch (error) { console .error ('JSON 解析失败:' , error); return defaultValue; } }
2.2.2 JSON.stringify(value, replacer?, space?) JSON.stringify 将 JavaScript 值序列化为 JSON 字符串。
1 2 3 4 const obj = { name : 'Alice' , age : 25 };const json = JSON .stringify (obj);console .log (json);
特殊值的处理 :
1 2 3 4 5 6 7 8 9 10 11 12 13 const obj = { name : 'Alice' , age : 25 , undefined : undefined , fn : function ( ) {}, symbol : Symbol ('test' ), date : new Date (), arr : [1 , undefined , 3 ] }; const json = JSON .stringify (obj);console .log (json);
replacer 参数 :
replacer 可以是函数或数组。
1. 函数形式 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const obj = { name : 'Alice' , age : 25 , password : 'secret' }; const json = JSON .stringify (obj, (key, value ) => { if (key === 'password' ) { return undefined ; } return value; }); console .log (json);
2. 数组形式 :
1 2 3 4 5 6 7 8 9 10 const obj = { name : 'Alice' , age : 25 , password : 'secret' , email : 'alice@example.com' }; const json = JSON .stringify (obj, ['name' , 'age' ]);console .log (json);
space 参数 :
space 用于控制缩进,便于阅读。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 const obj = { name : 'Alice' , age : 25 , hobbies : ['reading' , 'game' ] };console .log (JSON .stringify (obj));console .log (JSON .stringify (obj, null , 2 ));console .log (JSON .stringify (obj, null , '\t' ));
toJSON 方法 :
对象可以实现 toJSON 方法来自定义序列化行为。
1 2 3 4 5 6 7 8 9 10 11 12 13 const obj = { name : 'Alice' , date : new Date (), toJSON ( ) { return { name : this .name , date : this .date .toISOString () }; } }; console .log (JSON .stringify (obj));
2.2.3 常见坑与解决方案 1. 循环引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const obj = {};obj.self = obj; JSON .stringify (obj); function stringifyCircular (obj ) { const seen = new WeakSet (); return JSON .stringify (obj, (key, value ) => { if (typeof value === 'object' && value !== null ) { if (seen.has (value)) { return '[Circular]' ; } seen.add (value); } return value; }); }
2. Date 对象
1 2 3 4 5 6 7 8 9 10 11 12 13 const obj = { date : new Date () };const json = JSON .stringify (obj);console .log (json); const parsed = JSON .parse (json, (key, value ) => { if (key === 'date' ) { return new Date (value); } return value; }); console .log (parsed.date instanceof Date );
3. 大整数精度问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const bigInt = 9007199254740992 ; console .log (JSON .stringify ({ id : bigInt }));const bigger = 9007199254740993 ; console .log (JSON .stringify ({ id : bigger }));const obj = { id : '9007199254740993' };console .log (JSON .stringify (obj));
4. undefined、函数、Symbol
1 2 3 4 5 6 7 8 9 const obj = { name : 'Alice' , undefined : undefined , fn : function ( ) {}, symbol : Symbol ('test' ) }; console .log (JSON .stringify (obj));
3. 其他内置对象 3.1 Date 对象 1 2 3 4 5 6 7 8 9 const now = new Date ();const specific = new Date ('2026-01-05' );const timestamp = new Date (1704412800000 );console .log (now.toISOString ()); console .log (now.toLocaleString ()); console .log (now.getTime ());
3.2 RegExp 对象 1 2 3 4 5 6 7 const regex = /pattern/ flags;const regex2 = new RegExp ('pattern' , 'flags' );const match = 'hello' .match (/l/g );console .log (match);
3.3 Math 对象 1 2 3 4 5 6 7 8 9 10 11 console .log (Math .PI ); console .log (Math .E ); console .log (Math .max (1 , 2 , 3 )); console .log (Math .min (1 , 2 , 3 )); console .log (Math .round (3.7 )); console .log (Math .floor (3.7 )); console .log (Math .ceil (3.2 )); console .log (Math .random ());
4. 实战应用场景 4.1 数组去重 1 2 3 4 5 6 7 8 9 10 11 12 13 14 const arr = [1 , 2 , 2 , 3 , 3 , 3 ];const unique = [...new Set (arr)];const unique2 = arr.filter ((item, index ) => arr.indexOf (item) === index);const unique3 = arr.reduce ((acc, item ) => { if (!acc.includes (item)) { acc.push (item); } return acc; }, []);
4.2 深拷贝 1 2 3 4 5 6 function deepClone (obj ) { return JSON .parse (JSON .stringify (obj)); }
4.3 数据转换 1 2 3 4 5 6 7 8 9 const arr = [['a' , 1 ], ['b' , 2 ]];const obj = Object .fromEntries (arr);console .log (obj); const obj2 = { a : 1 , b : 2 };const arr2 = Object .entries (obj2);console .log (arr2);
5. 代码片段速查 5.1 数组操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 const unique = [...new Set (arr)];const flat = arr.flat (Infinity );const groupBy = (arr, key ) => arr.reduce ((acc, item ) => { const group = item[key]; if (!acc[group]) acc[group] = []; acc[group].push (item); return acc; }, {}); const chunk = (arr, size ) => Array .from ({ length : Math .ceil (arr.length / size) }, (_, i ) => arr.slice (i * size, i * size + size) );
5.2 Map/Set 操作 1 2 3 4 5 6 7 8 9 10 11 12 const mapToObj = map => Object .fromEntries (map);const objToMap = obj => new Map (Object .entries (obj));const intersection = (set1, set2 ) => new Set ([...set1].filter (x => set2.has (x))); const union = (set1, set2 ) => new Set ([...set1, ...set2]);
5.3 JSON 操作 1 2 3 4 5 6 7 8 9 10 11 const safeParse = (json, defaultValue = null ) => { try { return JSON .parse (json); } catch { return defaultValue; } }; const prettyJson = obj => JSON .stringify (obj, null , 2 );
6. 常见问题与解决方案 6.1 数组方法的选择
6.2 Map vs Object
6.3 Set vs Array
7. 速记与总结 7.1 核心概念速记
“数组有序可变长,类数组长得像但没方法。”
数组是有序集合,length 可读写;类数组有数值索引和 length,但没有数组方法。
“Map 键任意值,WeakMap 键必须对象且弱引用(不可遍历)。”
Map 的键可以是任意类型;WeakMap 的键必须是对象,弱引用,不可遍历。
“Set 去重看 SameValueZero,WeakSet 只装对象也弱引用。”
Set 自动去重,使用 SameValueZero 比较;WeakSet 只能存储对象,弱引用。
“TypedArray 固定长度、数值专用,适合高性能场景。”
TypedArray 长度固定,只存储数值,适合高性能计算。
“JSON 只认双引号、无函数无 undefined,parse/stringify 搭配 reviver/replacer 更灵活。”
JSON 格式严格;使用 reviver/replacer 可以自定义解析和序列化。
7.2 选择指南
需求
推荐数据结构
原因
有序元素集合
Array
最常用,功能丰富
键值对(对象键)
Map
支持对象作为键
键值对(弱引用)
WeakMap
不阻止垃圾回收
唯一值集合
Set
自动去重
对象标记(弱引用)
WeakSet
不阻止垃圾回收
高性能数值计算
TypedArray
固定长度,类型固定
数据交换
JSON
标准格式,广泛支持
7.3 最佳实践
数组操作优先使用不改变原数组的方法 (map、filter、slice)
需要对象作为键时使用 Map
需要去重时使用 Set
为对象存储元数据时使用 WeakMap
JSON 序列化时注意特殊值的处理
大整数使用字符串避免精度丢失
结语 :JavaScript 提供了丰富的数据结构,每种都有其适用场景。理解它们的特性和区别,能够帮助你选择最合适的数据结构,编写更高效、更易维护的代码。