你是不是也有过类似的经历?
- 后端返回的数据看起来正常,但JS就是解析不了
- 日期显示成一串看不懂的数字,还得手动转换
- 处理复杂数据时写了无数循环,代码又长又难维护
- 本地存储数据后再读取,发现格式全乱了
别担心,今天我就带你彻底掌握JSON和JS内置对象的使用技巧。学完这篇文章,你不仅能轻松解决这些问题,还能写出更优雅、更专业的数据处理代码!
JSON:数据交换的"普通话"
想象一下,你要跟一个外国朋友交流,但他说法语,你说中文,完全没法沟通怎么办?这时候就需要一种"通用语言"。
在编程世界里,JSON就是这种"通用语言"。它让前端、后端、移动端都能顺畅地"对话"。
JSON基础:比你想的还要简单
JSON说白了就是一种特殊格式的字符串,但它的规则超级严格:
1// 正确的JSON格式 2{ 3 "name": "张三", 4 "age": 25, 5 "isStudent": false, 6 "hobbies": ["篮球", "编程", "音乐"], 7 "address": { 8 "city": "北京", 9 "district": "海淀区" 10 } 11} 12 13// 常见的错误写法 14{ 15 name: "张三", // 错误:属性名必须用双引号 16 'age': 25, // 错误:必须用双引号,不能用单引号 17 isStudent: false, // 错误:属性名没加引号 18 hobbies: ["篮球", "编程", "音乐"] // 错误:属性名没加引号 19} 20
看到区别了吗?JSON的规则就是这么"死板",但正是这种严格保证了数据的一致性。
JSON的实战用法:不只是stringify和parse
你以为JSON就两个方法?那可就太小看它了!
1// 场景1:深拷贝对象的完美方案 2const originalObj = { 3 name: "李四", 4 scores: [90, 85, 95], 5 profile: { 6 height: 180, 7 weight: 70 8 } 9}; 10 11// 常用的浅拷贝有问题 12const shallowCopy = {...originalObj}; 13shallowCopy.profile.height = 190; // 这会修改原对象! 14 15// 用JSON实现深拷贝 16const deepCopy = JSON.parse(JSON.stringify(originalObj)); 17deepCopy.profile.height = 190; // 原对象不受影响 18console.log(originalObj.profile.height); // 还是180,完美! 19 20// 场景2:数据验证 - 确保拿到的是有效JSON 21function safeParse(jsonString) { 22 try { 23 return JSON.parse(jsonString); 24 } catch (error) { 25 console.log('JSON格式错误,返回默认值'); 26 return {}; 27 } 28} 29 30// 这样就不怕后端返回异常数据了 31const badData = "{name: '王五'}"; // 缺少引号的错误JSON 32const goodData = safeParse(badData); // 不会报错,返回空对象 33 34// 场景3:格式化显示,调试更轻松 35const complexData = { 36 users: [ 37 {id: 1, name: "用户1", permissions: ["read", "write"]}, 38 {id: 2, name: "用户2", permissions: ["read"]} 39 ] 40}; 41 42// 第三个参数是缩进空格数,让输出更美观 43console.log(JSON.stringify(complexData, null, 2)); 44
内置对象:JS自带的"瑞士军刀"
如果说JSON是数据交换的工具,那内置对象就是数据处理的多功能工具箱。每个都有独特的本领,用对了能让你的代码效率翻倍!
Date对象:告别时间处理的头疼
时间处理是前端最常见的需求,也是最容易出bug的地方。
1// 创建日期对象的多种方式 2const now = new Date(); // 当前时间 3const specificDate = new Date('2024-03-20'); // 特定日期 4const timestamp = new Date(1647763200000); // 通过时间戳 5 6// 实战:格式化日期显示 7function formatDate(date) { 8 const year = date.getFullYear(); 9 const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始,要+1 10 const day = String(date.getDate()).padStart(2, '0'); 11 12 return `${year}-${month}-${day}`; 13} 14 15// 用法示例 16const today = new Date(); 17console.log(formatDate(today)); // "2024-03-20" 18 19// 更实用的:相对时间显示 20function getRelativeTime(time) { 21 const now = new Date(); 22 const diffInMs = now - time; 23 const diffInMinutes = Math.floor(diffInMs / (1000 * 60)); 24 const diffInHours = Math.floor(diffInMs / (1000 * 60 * 60)); 25 const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24)); 26 27 if (diffInMinutes < 1) return '刚刚'; 28 if (diffInMinutes < 60) return `${diffInMinutes}分钟前`; 29 if (diffInHours < 24) return `${diffInHours}小时前`; 30 if (diffInDays < 7) return `${diffInDays}天前`; 31 32 return formatDate(time); 33} 34 35// 测试相对时间 36const testTime = new Date(Date.now() - 2 * 60 * 60 * 1000); // 2小时前 37console.log(getRelativeTime(testTime)); // "2小时前" 38
Math对象:数学计算不用愁
Math对象提供了一整套数学工具,很多开发者却只用了Math.random()。
1// 实用技巧1:生成指定范围的随机数 2function getRandomInRange(min, max) { 3 return Math.floor(Math.random() * (max - min + 1)) + min; 4} 5 6// 生成6位数字验证码 7const verificationCode = getRandomInRange(100000, 999999); 8console.log(verificationCode); // 比如:384756 9 10// 实用技巧2:数值限制在范围内 11function clamp(value, min, max) { 12 return Math.min(Math.max(value, min), max); 13} 14 15// 页面滚动进度计算 16const scrollProgress = clamp(window.scrollY / document.body.scrollHeight, 0, 1); 17console.log(scrollProgress); // 永远在0-1之间 18 19// 实用技巧3:小数精度处理 20const price = 19.899999; 21console.log(price.toFixed(2)); // "19.90" - 自动四舍五入 22 23// 但toFixed返回的是字符串,需要转数字 24const cleanPrice = Number(price.toFixed(2)); 25console.log(cleanPrice); // 19.9 26
String对象:文本处理的艺术
字符串处理是日常开发的重头戏,掌握这些技巧能省下大量时间。
1// 现代JS字符串处理技巧 2const text = " Hello, JavaScript世界! "; 3 4// 1. 去除空格的新方法 5console.log(text.trim()); // "Hello, JavaScript世界!" 6 7// 2. 检查字符串包含关系 8console.log(text.includes("JavaScript")); // true 9console.log(text.startsWith(" Hello")); // true 10console.log(text.endsWith("世界! ")); // true 11 12// 3. 字符串填充,适合显示对齐 13const number = "25"; 14console.log(number.padStart(4, "0")); // "0025" 15console.log(number.padEnd(4, "0")); // "2500" 16 17// 实战:关键词高亮函数 18function highlightKeywords(text, keywords) { 19 let result = text; 20 21 keywords.forEach(keyword => { 22 const regex = new RegExp(`(${keyword})`, 'gi'); 23 result = result.replace(regex, '<mark>$1</mark>'); 24 }); 25 26 return result; 27} 28 29// 使用示例 30const article = "JavaScript是一种强大的编程语言,学习JavaScript很有趣"; 31const highlighted = highlightKeywords(article, ["JavaScript", "编程"]); 32console.log(highlighted); 33// "<mark>JavaScript</mark>是一种强大的<mark>编程</mark>语言,学习<mark>JavaScript</mark>很有趣" 34
实战案例:构建一个完整的数据处理工具
光说不练假把式,我们来写一个真实可用的数据处理工具。
1class DataProcessor { 2 constructor() { 3 this.cache = new Map(); // 用Map做缓存,比普通对象更合适 4 } 5 6 // 处理API返回的数据 7 processApiResponse(apiData) { 8 try { 9 // 1. 深拷贝原始数据 10 const data = JSON.parse(JSON.stringify(apiData)); 11 12 // 2. 处理日期字段 13 if (data.createTime) { 14 data.createTime = new Date(data.createTime); 15 data.formattedTime = this.formatDate(data.createTime); 16 } 17 18 // 3. 处理数字字段 19 if (data.price) { 20 data.formattedPrice = [`¥${Number(data.price).toFixed(2)}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.data.md); 21 } 22 23 // 4. 缓存处理结果 24 this.cache.set(apiData.id, data); 25 26 return data; 27 } catch (error) { 28 console.error('数据处理失败:', error); 29 return null; 30 } 31 } 32 33 // 格式化日期 34 formatDate(date) { 35 const now = new Date(); 36 const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); 37 const targetDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); 38 39 const diffTime = targetDate - today; 40 const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24)); 41 42 if (diffDays === 0) return '今天'; 43 if (diffDays === 1) return '明天'; 44 if (diffDays === -1) return '昨天'; 45 46 return [`${date.getMonth() + 1}月${date.getDate()}日`](https://xplanc.org/primers/document/zh/10.Bash/90.%E5%B8%AE%E5%8A%A9%E6%89%8B%E5%86%8C/EX.date.md); 47 } 48 49 // 生成唯一ID 50 generateId(prefix = 'item') { 51 const timestamp = Date.now().toString(36); 52 const randomStr = Math.random().toString(36).substr(2, 5); 53 return `${prefix}_${timestamp}_${randomStr}`; 54 } 55} 56 57// 使用示例 58const processor = new DataProcessor(); 59 60// 模拟API数据 61const mockApiData = { 62 id: 1, 63 title: "JavaScript高级程序设计", 64 price: 89.9, 65 createTime: "2024-03-19T10:30:00Z", 66 tags: ["编程", "前端", "JavaScript"] 67}; 68 69const processedData = processor.processApiResponse(mockApiData); 70console.log(processedData); 71// 输出: 72// { 73// id: 1, 74// title: "JavaScript高级程序设计", 75// price: 89.9, 76// createTime: Date对象, 77// formattedTime: "昨天", 78// formattedPrice: "¥89.90", 79// tags: ["编程", "前端", "JavaScript"] 80// } 81
避坑指南:这些错误千万别犯!
在实际项目中,我见过太多因为不了解细节而导致的bug:
1// 坑1:JSON不能处理undefined和函数 2const problemObj = { 3 name: "测试", 4 method: function() { console.log('hello'); }, // 函数会被忽略 5 undefinedField: undefined // undefined会被忽略 6}; 7 8console.log(JSON.stringify(problemObj)); 9// 输出:{"name":"测试"} - 函数和undefined都没了! 10 11// 坑2:日期对象序列化会变成字符串 12const dateObj = { createTime: new Date() }; 13const serialized = JSON.stringify(dateObj); 14console.log(serialized); // {"createTime":"2024-03-20T03:45:30.123Z"} 15const parsed = JSON.parse(serialized); 16console.log(parsed.createTime instanceof Date); // false!变成了字符串 17 18// 解决方案:使用reviver函数 19const fixedParse = JSON.parse(serialized, (key, value) => { 20 if (typeof value === 'string' && 21 /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(value)) { 22 return new Date(value); 23 } 24 return value; 25}); 26console.log(fixedParse.createTime instanceof Date); // true! 27 28// 坑3:数字精度问题 29console.log(0.1 + 0.2 === 0.3); // false! 30console.log(0.1 + 0.2); // 0.30000000000000004 31 32// 解决方案:使用toFixed或者乘以10的倍数 33function safeAdd(num1, num2) { 34 const multiplier = Math.pow(10, 10); // 根据精度需求调整 35 return (num1 * multiplier + num2 * multiplier) / multiplier; 36} 37console.log(safeAdd(0.1, 0.2) === 0.3); // true! 38
进阶技巧:让代码更优雅的秘诀
当你掌握了基础之后,来看看这些让代码更专业的技巧:
1// 技巧1:使用Object.entries和Object.fromEntries 2const user = { 3 name: "张三", 4 age: 25, 5 city: "北京" 6}; 7 8// 过滤出年龄大于20的属性 9const filtered = Object.fromEntries( 10 Object.entries(user).filter(([key, value]) => { 11 if (key === 'age') return value > 20; 12 return true; 13 }) 14); 15console.log(filtered); // {name: "张三", age: 25, city: "北京"} 16 17// 技巧2:使用Map代替对象作为字典 18// 普通对象的键只能是字符串,Map可以是任意类型 19const complexKey = { id: 1 }; 20const myMap = new Map(); 21myMap.set(complexKey, "对应的值"); 22console.log(myMap.get(complexKey)); // "对应的值" 23 24// 技巧3:使用Set数组去重 25const duplicateArray = [1, 2, 2, 3, 4, 4, 5]; 26const uniqueArray = [...new Set(duplicateArray)]; 27console.log(uniqueArray); // [1, 2, 3, 4, 5] 28
总结与思考
今天我们一起深入探索了JSON和JS内置对象的强大能力。从基础用法到实战技巧,从常见坑点到进阶方法,希望这些内容能真正帮到你。
《告别数据混乱!掌握JSON与内置对象,让你的JS代码更专业》 是转载文章,点击查看原文。