简体   繁体   English

如何检查结构化克隆算法是否可以克隆对象

[英]How to check if an object can be cloned by the structured clone algorithm

The structured clone algorithm is a serialization algorithm used, among other things, to pass data between windows via window.postMessage . 结构化克隆算法是一种序列化算法,用于通过window.postMessage在窗口之间传递数据。 It supports recursive objects (unlike JSON) but not things like DOM Nodes, Functions, and Errors, and other 它支持递归对象(与JSON不同),但不支持DOM节点,函数和错误等

What I'd like is a simple way to check if a given object can be serialized by the structured clone algorithm. 我想要的是一种检查给定对象是否可以通过结构化克隆算法序列化的简单方法。 I could recursively walk the object and check if each property is a DOM Node, Function, or Error, but that's not a complete answer, and I was wondering if there was a better way. 我可以递归地遍历对象并检查每个属性是否是DOM节点,函数或错误,但这不是一个完整的答案,我想知道是否有更好的方法。

From the spec , I think it would be something like 规范来看,我认为它会是这样的

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;
  }
}

Note this has some limitations: 请注意,这有一些限制:

  • I can't check if an object has a [[DataView]] internal slot 我无法检查对象是否有[[DataView]]内部插槽
  • {}.toString is not a reliable way to get the [[Class]], but is the only one. {}.toString不是获取[[Class]]的可靠方法,但却是唯一的方法。
  • Other specifications may define how to clone additional kinds of objects 其他规范可以定义如何克隆其他类型的对象

So it may be more reliable to attempt to run the algorithm, and see if it produces some error: 因此,尝试运行算法可能更可靠,并查看它是否会产生一些错误:

function canBeCloned(val) {
  try {
    window.postMessage(val,'*');
  } catch(err) {
    return false;
  }
  return true;
}

Note if you have a message event listener, it will be called. 请注意,如果您有message事件侦听器,则会调用它。 If you want to avoid this, send the value to another window. 如果要避免这种情况,请将值发送到另一个窗口。 For example, you can create one using an iframe: 例如,您可以使用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;
  };
})();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM