为何无法克隆Selection对象?四种常规克隆方法失效的原因与解决
为什么常规克隆方法无法复制Selection对象?
问题背景
尝试了四种方法克隆Selection对象,但均无法成功:
- 使用
Object.assign()、扩展运算符、JSON.stringify()这三种方法均返回空对象; - 使用
structuredClone()方法则抛出DOMException错误:Uncaught DOMException: Failed to execute 'structuredClone' on 'Window': Selection object could not be cloned.
只有手动复制Selection对象的anchorNode、anchorOffset、focusNode、focusOffset属性,才能实现克隆。
无效的克隆代码示例
document.onselectionchange = function() { let selection = document.getSelection(); if( !selection.isCollapsed ) { var clone1 = Object.assign({}, selection); var clone2 = { ...selection }; var clone3 = JSON.stringify(selection); // 此方法会抛出错误 // Uncaught DOMException: Failed to execute 'structuredClone' on 'Window': Selection object could not be cloned. var clone4 = structuredClone(selection); } let {anchorNode, anchorOffset, focusNode, focusOffset} = selection; // anchorNode 和 focusNode 通常是文本节点 console.log("from.value", `${anchorNode["data"]}, offset ${anchorOffset}`) console.log("fto.value", `${focusNode["data"]}, offset ${focusOffset}`) }
有效的克隆代码示例
document.onselectionchange = function() { let selection = document.getSelection(); if( !selection.isCollapsed ) { var clone5 = {}; clone5.anchorNode = selection.anchorNode; clone5.anchorOffset = selection.anchorOffset; clone5.focusOffset = selection.focusOffset; clone5.focusNode = selection.focusNode; console.log("clone5", clone5); } let {anchorNode, anchorOffset, focusNode, focusOffset} = selection; // anchorNode 和 focusNode 通常是文本节点 console.log("from.value", `${anchorNode["data"]}, offset ${anchorOffset}`) console.log("fto.value", `${focusNode["data"]}, offset ${focusOffset}`) }
原因解析
Selection是宿主对象,属性不可枚举
Selection属于浏览器提供的宿主对象(而非原生JavaScript对象),它的公开属性(如anchorNode、focusOffset等)默认是不可枚举的。而Object.assign()、扩展运算符{...obj}、JSON.stringify()这些方法都是通过遍历对象的可枚举属性来工作的,自然无法获取到Selection的属性值,最终返回空对象或空JSON字符串。structuredClone不支持DOM宿主对象
结构化克隆算法(structuredClone())的设计目的是克隆可序列化的JavaScript值,但它明确不支持克隆DOM节点、Selection这类与浏览器上下文深度绑定的宿主对象。这些对象依赖于浏览器的DOM环境,无法被独立序列化和复制,因此调用时会直接抛出DOMException。手动复制属性的可行性
虽然Selection的属性不可枚举,但它们是可访问的——你可以通过直接访问属性名的方式获取值。因此手动逐个复制这些关键属性,就能得到包含Selection核心信息的克隆对象。
内容的提问来源于stack exchange,提问作者Marian07
相关产品推荐
相关产品推荐

