结构化克隆算法是一种序列化算法,除其他外,用于通过window.postMessage
. 它支持递归对象(与 JSON 不同),但不支持 DOM 节点、函数和错误等
我想要的是一种简单的方法来检查给定对象是否可以通过结构化克隆算法进行序列化。我可以递归地遍历对象并检查每个属性是 DOM 节点、函数还是错误,但这不是一个完整的答案,我想知道是否有更好的方法。
结构化克隆算法是一种序列化算法,除其他外,用于通过window.postMessage
. 它支持递归对象(与 JSON 不同),但不支持 DOM 节点、函数和错误等
我想要的是一种简单的方法来检查给定对象是否可以通过结构化克隆算法进行序列化。我可以递归地遍历对象并检查每个属性是 DOM 节点、函数还是错误,但这不是一个完整的答案,我想知道是否有更好的方法。
从规范来看,我认为它会像
function canBeCloned(val) {
if(Object(val) !== val) // Primitive value
return true;
switch({}.toString.call(val).slice(8,-1)) { // Class
case 'Boolean': case 'Number': case 'String': case 'Date':
case 'RegExp': case 'Blob': case 'FileList':
case 'ImageData': case 'ImageBitmap': case 'ArrayBuffer':
return true;
case 'Array': case 'Object':
return Object.keys(val).every(prop => canBeCloned(val[prop]));
case 'Map':
return [...val.keys()].every(canBeCloned)
&& [...val.values()].every(canBeCloned);
case 'Set':
return [...val.keys()].every(canBeCloned);
default:
return false;
}
}
请注意,这有一些限制:
{}.toString
不是获得 [[Class]] 的可靠方法,但它是唯一的方法。所以尝试运行算法可能更可靠,看看它是否会产生一些错误:
function canBeCloned(val) {
try {
window.postMessage(val,'*');
} catch(err) {
return false;
}
return true;
}
请注意,如果您有一个message
事件侦听器,它将被调用。如果您想避免这种情况,请将值发送到另一个窗口。例如,您可以使用 iframe 创建一个:
var canBeCloned = (function() {
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
var win = iframe.contentWindow;
document.body.removeChild(iframe);
return function(val) {
try { win.postMessage(val, '*'); }
catch(err) { return false; }
return true;
};
})();