仕様から、私はそれが次のようなものになると思います
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;
}
}
これにはいくつかの制限があることに注意してください。
- オブジェクトに [[DataView]] 内部スロットがあるかどうかを確認できません
{}.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;
};
})();