js 格式化(长文讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新开坑项目:《Spring AI 项目实战》 正在持续爆肝中,基于 Spring AI + Spring Boot 3.x + JDK 21..., 点击查看 ;
  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

前言:为什么需要 JS 格式化?

在 JavaScript 开发中,数据的“格式化”是一个高频需求。无论是处理用户输入、渲染界面,还是与 API 交互,开发者都需要将数据转换为特定的呈现形式。例如,将日期显示为“YYYY-MM-DD”格式,或者将 JSON 数据以更易读的方式输出。格式化操作看似简单,但若理解不深入,可能会在项目中埋下潜在的 bug。本文将从基础到进阶,系统性地讲解 JS 格式化的核心概念与实战技巧,并通过实际案例帮助读者掌握这一关键技能。


核心概念解析:理解格式化的底层逻辑

什么是 JS 格式化?

JS 格式化指的是通过代码将原始数据转换为符合业务需求的字符串或结构化形式的过程。例如:

  • 数据类型转换:将数字转换为货币格式(如 $1,000.00)
  • 结构化输出:将对象转换为带有缩进的 JSON 字符串
  • 标准化表达:将日期对象转换为“2023-10-05”格式的字符串

格式化的三个核心维度

  1. 数据类型约束:确保输出符合预期的数据结构(如数字保留两位小数)
  2. 可读性优化:通过缩进、换行提升复杂数据的可读性
  3. 兼容性适配:针对不同场景调整输出格式(如国际化日期格式)

基础用法:常用格式化场景实战

场景一:JSON 数据格式化

基础语法:JSON.stringify()

const user = { name: "Alice", age: 30 };
// 默认输出无缩进的紧凑格式
console.log(JSON.stringify(user));
// 输出:{"name":"Alice","age":30}

进阶技巧:使用缩进参数

通过第三个参数指定缩进空格数,可生成更易读的 JSON 字符串:

// 参数2为缩进空格数
console.log(JSON.stringify(user, null, 2));
// 输出:
// {
//   "name": "Alice",
//   "age": 30
// }

特殊需求:自定义序列化规则

通过 replacer 函数过滤或转换数据:

// 过滤年龄字段
console.log(JSON.stringify(user, ["name"], 2));
// 输出:
// {
//   "name": "Alice"
// }

场景二:字符串模板格式化

模板字符串的基础用法

ES6 引入的模板字符串简化了字符串拼接:

const greeting = `Hello, ${user.name}!`;
console.log(greeting); // Hello, Alice!

高级技巧:自定义标签函数

通过标签函数实现复杂格式化逻辑:

function formatString(strings, ...values) {
  return strings.reduce((acc, str, i) => 
    acc + str + (values[i] ? values[i].toUpperCase() : ''), 
  '');
}

const result = formatString`Welcome ${user.name}!`;
console.log(result); // Welcome ALICE!

场景三:日期格式化

原生 Date 对象的局限性

const date = new Date();
console.log(date.toString());
// 输出类似:Wed Oct 04 2023 14:30:00 GMT+0800 (China Standard Time)

手动拼接实现基础格式

function formatDate(date) {
  return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
}

console.log(formatDate(new Date())); // 2023-10-04

强力推荐:Intl.DateTimeFormat API

const options = { year: 'numeric', month: '2-digit', day: '2-digit' };
console.log(new Intl.DateTimeFormat('zh-CN', options).format(new Date()));
// 输出:2023/10/04(根据本地化设置自动调整格式)

进阶技巧:构建灵活的格式化系统

抽象公共逻辑:函数封装

// 数字格式化工具
const formatNumber = (num, decimals = 2) => {
  return num.toFixed(decimals).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
};

console.log(formatNumber(1234567.8910)); // 1,234,567.89

策略模式:可配置的格式化方案

const formatters = {
  currency: (value) => `$${formatNumber(value)}`,
  percentage: (value) => `${(value * 100).toFixed(1)}%`,
};

function applyFormat(value, type) {
  return formatters[type]?.(value) || value;
}

console.log(applyFormat(9999.99, 'currency')); // $9,999.99

自定义 JSON 缩进渲染

通过递归函数实现深度缩进控制:

function prettyPrintJson(obj, indent = 2) {
  return JSON.stringify(obj, null, indent)
    .replace(/(\n *)(\{|\[)\s*\n/g, '$1$2 ')
    .replace(/\s*\n */g, ' ');
}

console.log(prettyPrintJson({ a: [1,2,3], b: { c: true } }, 4));
// 输出:
// {
//     "a": [1,2,3],
//     "b": {"c": true}
// }

实战案例:构建日志格式化系统

需求背景

开发一个支持多格式的日志记录工具,要求:

  1. 自动添加时间戳
  2. 区分日志等级(INFO/WARNING/ERROR)
  3. 支持 JSON 或普通字符串输出

实现方案

class Logger {
  constructor(options = {}) {
    this.format = options.format || 'string';
    this.timezone = options.timezone || 'UTC';
  }

  log(level, message, data = {}) {
    const timestamp = new Date().toLocaleString('en-US', {
      timeZone: this.timezone,
    });
    
    const logEntry = {
      timestamp,
      level,
      message,
      ...data,
    };

    if (this.format === 'json') {
      console.log(JSON.stringify(logEntry, null, 2));
    } else {
      console.log(`[${timestamp}] ${level}: ${message}`);
    }
  }
}

// 使用示例
const logger = new Logger({ format: 'json', timezone: 'Asia/Shanghai' });
logger.log('ERROR', 'Database connection failed', { code: 500 });

输出效果(JSON 格式)

{
  "timestamp": "10/4/2023, 6:30:00 PM",
  "level": "ERROR",
  "message": "Database connection failed",
  "code": 500
}

性能优化与最佳实践

避免过度格式化

  • 按需格式化:仅在必要时进行格式化(如输出到 UI 或日志)
  • 缓存结果:对频繁使用的格式化结果进行缓存

国际化支持

  • 使用 Intl API 处理:
    • 数字格式化Intl.NumberFormat
    • 货币格式Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' })
    • 日期本地化Intl.DateTimeFormat('ja-JP')

安全性注意事项

  • 特殊字符转义:在输出 HTML 内容时使用 encodeURIComponent
  • 数据过滤:对用户输入的格式化参数进行白名单校验

常见问题解答

Q1:JSON 格式化后出现特殊符号怎么办?

当数据包含特殊字符(如 ")时,JSON.stringify 会自动添加转义符 \。若需去除,可通过正则表达式处理:

const safeJson = JSON.stringify(data).replace(/\\n/g, '\\n').replace(/\\r/g, '\\r');

Q2:如何实现自定义的日期格式?

通过组合 Date 方法和字符串拼接:

function customDateFormat(date, format) {
  const tokens = {
    'YYYY': date.getFullYear(),
    'MM': String(date.getMonth() + 1).padStart(2, '0'),
    'DD': String(date.getDate()).padStart(2, '0'),
  };
  return format.replace(/YYYY|MM|DD/g, (token) => tokens[token]);
}

console.log(customDateFormat(new Date(), 'YYYY-MM-DD')); // 2023-10-04

Q3:如何在模板字符串中动态插入格式化函数?

function currencyFormat(value) {
  return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(value);
}

const total = 99.99;
console.log(`Total: ${currencyFormat(total)}`); // Total: $99.99

结论:格式化能力的进阶之路

掌握 JS 格式化技能,本质上是理解数据表达与业务需求之间的“翻译”过程。从基础的 JSON.stringify 到进阶的自定义格式化系统,开发者需要根据项目需求选择合适的技术方案。本文通过具体案例展示了格式化的多种实现路径,建议读者在实践中:

  1. 将常用格式封装为可复用函数
  2. 使用类型检查工具确保输入数据的合法性
  3. 结合代码规范工具(如 ESLint)统一格式标准

格式化不仅是技术问题,更是提升开发效率、增强代码可维护性的关键环节。通过持续实践与优化,开发者可以将格式化能力内化为日常开发的“隐形武器”,在面对复杂数据场景时游刃有余。

最新发布