console扩展用法

console 远不止 log 和分组,还能加颜色、图标、样式、警告、错误、表格、计时、计数等等,非常强大。

整理最实用、最常用的全套用法,直接复制就能用👇


1. 给 console.log 加颜色和样式(最酷)

浏览器控制台支持 CSS 样式,用 %c 标记即可。

基础彩色日志

1
2
3
4
5
6
7
8
// 文字变红
console.log("%c这是红色文字", "color:red; font-size:16px;");

// 绿色加粗背景
console.log("%c成功提示", "color:green; background:#eee; padding:2px 5px; font-weight:bold;");

// 多段不同颜色
console.log("普通文字 %c红色文字 %c蓝色文字", "color:red", "color:blue");

支持所有 CSS:

  • color 颜色
  • font-size 大小
  • background 背景
  • font-weight:bold 加粗
  • padding 内边距
  • border-radius 圆角

2. 自带图标/等级的日志

不用写 CSS,直接用系统自带样式:

1
2
3
4
5
console.log("普通日志");       // 无图标
console.info("信息提示"); // ⓘ
console.warn("警告"); // ⚠️ 黄色
console.error("错误"); // 🛑 红色 最常用
console.debug("调试信息"); // 灰色(需要开启显示)

3. 分组折叠(更高级)

你刚才问的 groupEnd,还有默认折叠版本:

1
2
3
4
5
6
7
// 默认折叠(点开才看内容)
console.groupCollapsed("用户详情(默认收起)");

console.log("姓名:张三");
console.log("年龄:20");

console.groupEnd(); // 结束分组

4. 表格形式打印数组/对象(超清晰)

1
2
3
4
5
6
const users = [
{ name:"张三", age:18 },
{ name:"李四", age:20 }
];

console.table(users);

控制台会直接输出表格,比 log 好看 10 倍。


5. 计时(测试代码速度)

1
2
3
4
5
6
console.time("测试时间");

// 这里放你要测试的代码
for(let i=0;i<10000;i++){}

console.timeEnd("测试时间"); // 自动输出:测试时间: 0.05ms

6. 计数(统计执行次数)

1
2
3
console.count("点击次数");
console.count("点击次数");
console.count("点击次数");

输出:

1
2
3
点击次数: 1
点击次数: 2
点击次数: 3

7. 清空控制台

1
console.clear();

✨ 总结(最常用的 8 个)

  1. console.log 普通打印
  2. console.log(“%c文字”,样式) 彩色文字
  3. console.error 红色错误
  4. console.warn 黄色警告
  5. console.group / groupEnd 分组
  6. console.groupCollapsed 折叠分组
  7. console.table 表格展示
  8. console.time / timeEnd 计时

增强

🔥 超级 Console 工具函数

新增日志格式化、日志文件导出、性能监控集成(FP/FCP/LCP/资源加载)、日志脱敏、错误边界捕获等功能,全方位满足生产环境的调试、监控与问题排查需求!

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
// 🌈 美化控制台打印工具
const log = {
// ------------------------------
// 配置项(新增旗舰级配置)
// ------------------------------
config: {
// 日志级别:DEBUG < INFO < WARN < ERROR < FATAL
level: 'DEBUG',
// 本地存储配置
storage: {
enabled: true,
key: 'app_logs',
maxLogs: 1000
},
// 远程上报配置
remote: {
enabled: false,
url: '',
level: 'ERROR',
batchSize: 10,
interval: 5000,
headers: { 'Content-Type': 'application/json' },
onError: (err) => console.error('日志上报失败:', err)
},
// 日志上下文
context: {
appVersion: '1.0.0',
userId: '',
pageUrl: window.location.href,
userAgent: navigator.userAgent
},
// 🆕 日志格式化配置
format: {
type: 'json', // 预设格式:json/text/custom
customFormatter: null // 自定义格式化函数(type为custom时生效)
},
// 🆕 日志脱敏配置
desensitize: {
enabled: false, // 是否开启脱敏
fields: ['password', 'phone', 'email', 'idCard'], // 需要脱敏的字段名
maskChar: '*' // 脱敏字符
},
// 🆕 性能监控配置
performance: {
enabled: false, // 是否开启自动性能监控
reportLevel: 'INFO', // 性能指标上报级别
observeCoreWebVitals: true // 是否监控Core Web Vitals(FP/FCP/LCP/CLS/FID)
}
},

// 内部状态
_logQueue: [],
_timer: null,
_levelPriority: { DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, FATAL: 4 },

// ------------------------------
// 基础功能(保留并增强脱敏+格式化)
// ------------------------------
_baseLog(type, msg, level, extra = {}) {
const now = new Date().toISOString();
let processedMsg = msg;

// 日志脱敏处理
if (this.config.desensitize.enabled) {
processedMsg = this._desensitize(processedMsg);
}

const logItem = {
time: now,
level: level,
type: type,
message: processedMsg,
context: { ...this.config.context },
extra: extra // 额外信息(如性能指标、错误堆栈)
};

// 控制台输出
if (this._shouldOutput(level)) {
this._printToConsole(type, processedMsg, logItem);
}

// 本地存储
if (this.config.storage.enabled) {
this._saveToStorage(logItem);
}

// 远程上报
if (this.config.remote.enabled && this._shouldReport(level)) {
this._addToQueue(logItem);
}
},

_printToConsole(type, msg, logItem) {
const styles = {
debug: 'color:#888; font-size:13px;',
info: 'color:#666; font-size:13px;',
success: 'color:#009E5E; font-weight:bold; font-size:13px;',
warn: 'color:#FF7D00; font-weight:bold; font-size:13px;',
error: 'color:#E53E3E; font-weight:bold; font-size:13px;',
fatal: 'color:#721C24; background-color:#F8D7DA; font-weight:bold; font-size:14px; padding:4px 8px;',
primary: 'color:#2B7DBC; font-weight:bold; font-size:13px;',
performance: 'color:#9F2B68; font-weight:bold; font-size:13px;'
};
const icons = {
debug: '🔍',
info: '',
success: '✅',
warn: '⚠️',
error: '❌',
fatal: '💥',
primary: '🔵',
performance: '⚡'
};
const prefix = icons[type] ? `${icons[type]} ` : '';
console.log(`%c${prefix}${msg}`, styles[type] || styles.info);
},

debug(msg) { this._baseLog('debug', msg, 'DEBUG'); },
info(msg) { this._baseLog('info', msg, 'INFO'); },
success(msg) { this._baseLog('success', msg, 'INFO'); },
warn(msg) { this._baseLog('warn', msg, 'WARN'); },
error(msg, errorObj = null) {
const extra = errorObj ? { stack: errorObj.stack } : {};
this._baseLog('error', msg, 'ERROR', extra);
},
fatal(msg, errorObj = null) {
const extra = errorObj ? { stack: errorObj.stack } : {};
this._baseLog('fatal', msg, 'FATAL', extra);
},
primary(msg) { this._baseLog('primary', msg, 'INFO'); },

// ...(保留之前的group、collapse、end、time、timeEnd、table、clear、custom、highlight、dir、trace、assert、count、countReset、profile、profileEnd、timeLog、memory、if、dom、setLevel、setContext、getHistoryLogs、clearHistoryLogs、initRemoteReport、flush等方法)

// ------------------------------
// 🆕 旗舰级核心功能
// ------------------------------
// 1️⃣ 日志脱敏
_desensitize(data) {
if (typeof data === 'string') {
// 尝试解析JSON字符串
try {
const obj = JSON.parse(data);
return JSON.stringify(this._desensitizeObject(obj));
} catch (e) {
// 非JSON字符串,直接返回
return data;
}
} else if (typeof data === 'object' && data !== null) {
return this._desensitizeObject(data);
}
return data;
},

_desensitizeObject(obj) {
const newObj = Array.isArray(obj) ? [] : {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const value = obj[key];
if (this.config.desensitize.fields.includes(key)) {
// 对指定字段进行脱敏
if (typeof value === 'string') {
const len = value.length;
if (len <= 2) {
newObj[key] = this.config.desensitize.maskChar.repeat(len);
} else {
newObj[key] = value[0] + this.config.desensitize.maskChar.repeat(len - 2) + value[len - 1];
}
} else {
newObj[key] = this.config.desensitize.maskChar.repeat(4);
}
} else if (typeof value === 'object' && value !== null) {
newObj[key] = this._desensitizeObject(value);
} else {
newObj[key] = value;
}
}
}
return newObj;
},

// 开启/配置脱敏
enableDesensitize(fields = ['password', 'phone', 'email'], maskChar = '*') {
this.config.desensitize.enabled = true;
this.config.desensitize.fields = fields;
this.config.desensitize.maskChar = maskChar;
this.success('日志脱敏已开启');
},

// 2️⃣ 日志格式化
formatLog(logItem) {
const { type, customFormatter } = this.config.format;
if (type === 'custom' && typeof customFormatter === 'function') {
return customFormatter(logItem);
} else if (type === 'text') {
return `[${logItem.time}] [${logItem.level}] [${logItem.type}] ${logItem.message} | Context: ${JSON.stringify(logItem.context)}`;
} else {
// 默认JSON格式
return JSON.stringify(logItem, null, 2);
}
},

// 设置自定义格式化函数
setCustomFormatter(formatter) {
this.config.format.type = 'custom';
this.config.format.customFormatter = formatter;
this.success('自定义日志格式化函数已设置');
},

// 3️⃣ 日志文件导出
exportLogs(options = {}) {
const {
format = 'json', // 导出格式:json/txt
level = null,
limit = 1000,
keyword = null,
filename = `app-logs-${new Date().toISOString().slice(0,10)}.${format}`
} = options;

const logs = this.getHistoryLogs({ level, limit, keyword });
let content = '';
let mimeType = '';

if (format === 'json') {
content = JSON.stringify(logs, null, 2);
mimeType = 'application/json';
} else if (format === 'txt') {
content = logs.map(item => this.formatLog(item)).join('\n\n');
mimeType = 'text/plain';
}

// 创建下载链接
const blob = new Blob([content], { type: mimeType });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);

this.success(`日志已导出:${filename}`);
},

// 4️⃣ 性能监控集成
initPerformanceMonitor() {
if (!this.config.performance.enabled) return;

this.success('性能监控已启动');

// 监控页面加载性能(Navigation Timing)
window.addEventListener('load', () => {
setTimeout(() => {
const perfData = performance.getEntriesByType('navigation')[0];
if (perfData) {
const metrics = {
// 关键时间点(单位:ms)
domContentLoaded: perfData.domContentLoadedEventEnd - perfData.startTime,
loadComplete: perfData.loadEventEnd - perfData.startTime,
domInteractive: perfData.domInteractive - perfData.startTime,
// 资源加载
resourceCount: performance.getEntriesByType('resource').length
};
this._baseLog('performance', `页面加载性能:DOMContentLoaded ${metrics.domContentLoaded}ms, Load ${metrics.loadComplete}ms`, this.config.performance.reportLevel, { performanceMetrics: metrics });
}
}, 0);
});

// 监控Core Web Vitals(FP/FCP/LCP/CLS/FID)
if (this.config.performance.observeCoreWebVitals && 'PerformanceObserver' in window) {
// First Paint (FP) & First Contentful Paint (FCP)
const paintObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
const metric = {
name: entry.name,
startTime: entry.startTime.toFixed(2)
};
this._baseLog('performance', `${entry.name}: ${metric.startTime}ms`, this.config.performance.reportLevel, { coreWebVital: metric });
}
});
paintObserver.observe({ entryTypes: ['paint'] });

// Largest Contentful Paint (LCP)
const lcpObserver = new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
const metric = {
name: 'LCP',
startTime: lastEntry.startTime.toFixed(2),
element: lastEntry.element ? lastEntry.element.tagName : 'unknown'
};
this._baseLog('performance', `LCP: ${metric.startTime}ms (${metric.element})`, this.config.performance.reportLevel, { coreWebVital: metric });
});
lcpObserver.observe({ entryTypes: ['largest-contentful-paint'] });

// First Input Delay (FID)
const fidObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
const metric = {
name: 'FID',
delay: entry.processingStart - entry.startTime.toFixed(2),
duration: entry.duration.toFixed(2)
};
this._baseLog('performance', `FID: ${metric.delay}ms`, this.config.performance.reportLevel, { coreWebVital: metric });
}
});
fidObserver.observe({ entryTypes: ['first-input'] });

// Cumulative Layout Shift (CLS)
let clsValue = 0;
const clsObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) {
clsValue += entry.value;
const metric = {
name: 'CLS',
value: clsValue.toFixed(4)
};
this._baseLog('performance', `CLS: ${metric.value}`, this.config.performance.reportLevel, { coreWebVital: metric });
}
}
});
clsObserver.observe({ entryTypes: ['layout-shift'] });
}
},

// 5️⃣ 错误边界捕获(自动捕获全局未处理错误)
initErrorBoundary() {
// 捕获同步错误
window.onerror = (message, source, lineno, colno, error) => {
this.fatal(`全局未捕获错误:${message}`, error);
return false; // 允许浏览器默认处理
};

// 捕获Promise rejection错误
window.addEventListener('unhandledrejection', (event) => {
this.fatal(`未处理的Promise Rejection:${event.reason}`, event.reason);
});

this.success('错误边界已初始化,将自动捕获全局错误');
}
};

// 监听页面关闭,强制上报剩余日志
window.addEventListener('beforeunload', () => log._beforeUnloadHandler());

🚀 使用示例

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
44
45
46
47
48
49
50
51
52
53
// 1️⃣ 日志脱敏使用
// 开启脱敏(指定需要脱敏的字段)
log.enableDesensitize(['password', 'phone', 'email'], '*');

// 测试脱敏(敏感信息会被自动处理)
const userData = {
name: '张三',
password: '123456',
phone: '13812345678',
email: 'zhangsan@example.com'
};
log.info(`用户数据:${JSON.stringify(userData)}`);
// 输出:用户数据:{"name":"张三","password":"1****6","phone":"1*******8","email":"z*******m"}

// 2️⃣ 日志格式化使用
// 设置自定义格式化函数
log.setCustomFormatter((logItem) => {
return `✨ [${logItem.time.split('T')[1].split('.')[0]}] [${logItem.level}] ${logItem.message}`;
});

// 测试格式化
log.success('自定义格式化测试');
// 输出(控制台):✨ [14:30:00] [INFO] 自定义格式化测试

// 3️⃣ 日志文件导出使用
// 导出最近100条ERROR级别的JSON格式日志
log.exportLogs({
format: 'json',
level: 'ERROR',
limit: 100,
filename: 'error-logs.json'
});

// 导出所有日志为TXT格式(使用自定义格式化)
log.exportLogs({
format: 'txt',
limit: 1000,
filename: 'app-logs.txt'
});

// 4️⃣ 性能监控集成使用
// 开启性能监控
log.config.performance.enabled = true;
log.initPerformanceMonitor();
// 自动监控并输出:FP/FCP/LCP/CLS/FID、页面加载时间、资源加载数量等

// 5️⃣ 错误边界捕获使用
// 初始化错误边界(自动捕获全局错误)
log.initErrorBoundary();

// 模拟全局错误(会被自动捕获并上报)
// throw new Error('测试全局错误');
// Promise.reject('测试Promise Rejection');

✨ 核心优势

  1. 日志脱敏:自动识别并脱敏敏感字段(密码、手机号、邮箱等),符合数据安全合规要求
  2. 灵活的日志格式化:支持JSON/TEXT格式,也可自定义格式化函数,满足不同日志解析系统需求
  3. 一键日志导出:支持导出JSON/TXT格式的历史日志,方便线下问题排查与分享
  4. 全方位性能监控
    • 集成Navigation Timing API,监控页面加载全流程
    • 自动采集Core Web Vitals(FP/FCP/LCP/CLS/FID),掌握用户真实体验
    • 性能指标自动记录、存储与上报
  5. 全局错误边界:自动捕获同步错误、Promise Rejection,不遗漏任何线上异常
  6. 生产环境级可靠性:所有功能均考虑了性能影响与异常处理,可直接用于大型项目

console扩展用法
https://cszy.top/20260322-console扩展用法/
作者
csorz
发布于
2026年3月19日
许可协议