如何正确序列化MutationRecord对象?JSON.stringify返回空对象问题
MutationRecord 序列化得到空对象的解决方法
问题根因
你遇到的JSON.stringify(mutation)输出{}的核心原因是:
MutationRecord 接口的所有核心属性(包括变更类型、节点列表、目标节点、旧值等)都定义在MutationRecord.prototype原型上,属于带 getter 的访问器属性,并非实例自身的可枚举属性。
JSON.stringify的序列化规则只会提取对象自身可枚举的属性,会直接跳过两类属性:
- 沿原型链继承的属性
- 非自身可枚举的属性
因此最终扫描不到任何有效字段,输出空对象。console.log能正常展示完整结构,是因为浏览器控制台会自动递归展示对象原型链上的可访问属性,和序列化的执行逻辑完全不同。
正确实现方案
由于无法通过JSON.stringify直接读取原型链上的属性,需要手动提取MutationRecord的所有标准字段,构造一个普通的纯对象,再对这个纯对象做序列化。
同时需要注意:MutationRecord里包含的DOM节点、NodeList类型的值,无法直接序列化(会出现循环引用、空对象等问题),需要提前做适配转换。
通用序列化工具函数
function serializeMutationRecord(mutation) { // 适配DOM节点,转换为无循环引用的基础信息 const serializeNode = (node) => { if (!node || !node.nodeType) return null; return { nodeType: node.nodeType, nodeName: node.nodeName, id: node.id || null, // 截断长文本,避免序列化结果冗余 textContent: node.textContent?.slice(0, 50) } } // 适配NodeList,转换为序列化后的节点数组 const serializeNodeList = (nodeList) => { return Array.from(nodeList || []).map(serializeNode) } // 手动提取MutationRecord所有标准属性 return { type: mutation.type, target: serializeNode(mutation.target), addedNodes: serializeNodeList(mutation.addedNodes), removedNodes: serializeNodeList(mutation.removedNodes), previousSibling: serializeNode(mutation.previousSibling), nextSibling: serializeNode(mutation.nextSibling), attributeName: mutation.attributeName, attributeNamespace: mutation.attributeNamespace, oldValue: mutation.oldValue } }
使用方式
在原来的MutationObserver回调代码中,把直接序列化的部分替换即可:
function callback(mutationList, observer) { mutationList.forEach( (mutation) => { // 原直接序列化代码 JSON.stringify(mutation) 会输出 "{}" // 替换为手动提取字段后的序列化逻辑 const serializedMutation = JSON.stringify(serializeMutationRecord(mutation)) console.log(mutation, serializedMutation) switch(mutation.type) { case 'childList': /* 节点树中新增或移除了子节点,可通过mutation.addedNodes和mutation.removedNodes查看详情 */ break; case 'attributes': /* mutation.target元素的属性值发生变化,属性名存于mutation.attributeName,旧值存于mutation.oldValue */ break; } }); } const targetNode = document.querySelector("#someElement"); const observerOptions = { childList: true, attributes: true, // 省略(或设为false)则仅监听目标节点自身的变化 subtree: true } const observer = new MutationObserver(callback); observer.observe(targetNode, observerOptions); document.querySelector('#theButton').onclick = function() { targetNode.innerText = 'Random Value ' + Math.random()*100; }
对应配套的HTML结构无需改动:
<p id="someElement"> Some Value </p> <button id="theButton"> Update </button>
拓展说明
类似的序列化问题并非MutationRecord独有。所有浏览器内置的Web API对象(包括DOM节点、CSSStyleDeclaration、原生事件对象等),核心属性大多定义在原型链上,直接调用
JSON.stringify都会输出空对象,都需要通过手动提取字段、构造纯对象的方式完成序列化。
内容的提问来源于stack exchange,提问作者Jacksonkr
相关产品推荐
相关产品推荐

