一行代码让线上故障原地消失,却也可能是你未来数月噩梦的开始
一、前端“黑魔法”的五大实战场景
场景一:前端监控与性能分析
const originalFetch = window.fetch;window.fetch = function(...args) {const startTime = Date.now();return originalFetch(...args).then(response => {const duration = Date.now() - startTime;console.log(`[Monitor] 请求 ${args[0]} 耗时 ${duration}ms`);return response;});};
场景二:为所有请求自动添加身份验证
if (!window.fetch.__patched) {const originalFetch = window.fetch;window.fetch = function(input, init = {}) {const token = localStorage.getItem('auth_token');const newInit = {...init,headers: { ...init.headers, 'Authorization': `Bearer ${token}` }};return originalFetch(input, newInit);};window.fetch.__patched = true;}
场景三:为旧浏览器提供 Polyfill
if (!Array.prototype.includes) {Array.prototype.includes = function(searchElement, fromIndex) {return this.indexOf(searchElement, fromIndex) !== -1;};}
场景四:扩展或修复第三方库的行为
const originalCalculate = ThirdPartyLib.calculator.calculate;ThirdPartyLib.calculator.calculate = function(data) {const fixedData = data.map(item => item || 0);return originalCalculate(fixedData);};
场景五:单元测试与 Mock
const originalFetch = window.fetch;window.fetch = function(url) {if (url === '/api/user') {return Promise.resolve(new Response(JSON.stringify({id: 1, name: 'Test'})));}return originalFetch(url);};
二、DOM 操作的“黑魔法”四重奏
实例一:SPA 路由监控
const originalAppend = Node.prototype.appendChild;const rootContainer = document.getElementById('app');Node.prototype.appendChild = function(child) {const result = originalAppend.apply(this, arguments);if (this === rootContainer) {console.log('[PV监控] 新页面视图已挂载:', child.id);}return result;};
实例二:滚动性能优化
const originalAddListener = EventTarget.prototype.addEventListener;EventTarget.prototype.addEventListener = function(type, listener, options) {let newOptions = options;if (type === 'touchmove' || type === 'scroll' || type === 'wheel') {newOptions = { ...options, passive: true };}return originalAddListener.call(this, type, listener, newOptions);};
实例三:XSS 自动净化
const originDescriptor = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML');Object.defineProperty(Element.prototype, 'innerHTML', {get: function() { return originDescriptor.get.call(this); },set: function(htmlString) {const sanitized = htmlString.replace(/.*?<\/script>/gi, '');console.log('[安全拦截] 已过滤 XSS 内容');return originDescriptor.set.call(this, sanitized);}});
实例四:表单值变更追踪
const inputProto = HTMLInputElement.prototype;const originValueDescriptor = Object.getOwnPropertyDescriptor(inputProto, 'value');Object.defineProperty(inputProto, 'value', {get: function() { return originValueDescriptor.get.call(this); },set: function(newVal) {console.log('[表单追踪] input 值被 JS 修改为:', newVal);this.dispatchEvent(new CustomEvent('jsValueChange', { detail: { value: newVal } }));return originValueDescriptor.set.call(this, newVal);}});
三、“黑魔法”的代价:不可忽视的风险
无限递归:在补丁内部调用原方法时,必须使用originFn.apply(this, arguments),直接调用会引发死循环导致页面崩溃。
原型链顺序:务必确保补丁代码在所有业务脚本加载之前执行,否则业务脚本拿到的仍是未被修补的原生方法。
性能开销:DOM 操作极为高频,在补丁中加入过多同步计算会严重拖慢渲染速度。
夜雨聆风