Javascript 结构化克隆算法拒绝的类别
我正在寻求为IndexedDB polyfill(包括节点)忠实地实现结构化克隆算法。虽然该算法对某些类型的显式白名单基本上是清楚的,但我更不了解它的总体黑名单(以及如何检测此类黑名单类型) 结构化克隆算法: 默认情况下,平台对象不是可克隆对象 …其中“平台对象”是: 在一组IDL片段的给定实现中,可以将对象描述为平台对象、用户对象或两者都不是。有两种对象被视为平台对象:Javascript 结构化克隆算法拒绝的类别,javascript,clone,indexeddb,postmessage,Javascript,Clone,Indexeddb,Postmessage,我正在寻求为IndexedDB polyfill(包括节点)忠实地实现结构化克隆算法。虽然该算法对某些类型的显式白名单基本上是清楚的,但我更不了解它的总体黑名单(以及如何检测此类黑名单类型) 结构化克隆算法: 默认情况下,平台对象不是可克隆对象 …其中“平台对象”是: 在一组IDL片段的给定实现中,可以将对象描述为平台对象、用户对象或两者都不是。有两种对象被视为平台对象: 实现非回调接口的对象 表示IDL异常的对象 至于另一类(可能)不可克隆对象,SCA在将某些类型列入白名单后: 否则,如果
- 实现非回调接口的对象李>
- 表示IDL异常的对象
[[Call]]
(以及“所有ECMAScript函数对象都有此处定义的[[Call]]内部方法”)的IsCallable
,因此我排除了函数的“基本内部方法”,导致以下情况:
- [[GetPrototypeOf]、[[SetPrototypeOf]、[[IsExtensible]、[[PreventExtensions]、[[GetOwnProperty]、[[DefineOwnProperty]、[[HasProperty]、[[Get]、[[Set]、[[Delete]、[[OwnPropertyKeys]]
[[Clone]]
内部方法并因此可以被白名单的平台对象function throwUponDataCloneError (val) {
// Should also throw with:
// 1. `IsDetachedBuffer` (a process not called within the ECMAScript spec)
// 2. We are not dealing with `Blob`/`File` at this point as the
// IndexedDB spec requires synchronous rejection and we'd apparently
// have to use deprecated sync XHR (or `readFileSync` in Node) to get this
// 'Proxy' should be rejected but no apparent way to introspect on it
const stringTag = ({}.toString.call(val).slice(8, -1));
if (typeof val === 'symbol' || // Symbol's `toStringTag` is only "Symbol" for its initial value, so safer to check `typeof`
[
'Function', // All functions including bound function exotic objects; rejected per `IsCallable` check (could also be covered by `typeof === 'function'`)
'Arguments', // A non-array exotic object
'Error', // `Error` and other errors have the [[ErrorData]] internal slot and give "Error"
// The following checks are only based on the default expected `toStringTag` values
'Module', // A non-array exotic object
'Promise', // Promise instances have an extra slot ([[PromiseState]]) but not throwing in Chrome `postMessage`
'WeakMap', // WeakMap instances have an extra slot ([[WeakMapData]]) but not throwing in Chrome `postMessage`
'WeakSet' // WeakSet instances have an extra slot ([[WeakSetData]]) but not throwing in Chrome `postMessage`
].includes(stringTag) ||
val === Object.prototype || // A non-array exotic object but not throwing in Chrome `postMessage`
) {
throw new DOMException('The object cannot be cloned.', 'DataCloneError');
}
}
作为检测平台对象的一种手段,WebIDL声明:
实现一个或多个接口的平台对象的类字符串必须是平台对象的主接口的标识符
…其中“类字符串”是:
从对象.prototype.toString
返回的字符串中要包含的字符串。如果对象有类字符串,则在创建对象时,该对象必须有一个名为@@toStringTag
符号且值为指定字符串的属性
事实上,我可以找到一个SCA的JS实现,它采用这种方法来抛出任何未识别的@@toStringTag
然而,我感到关切的是:
@@toStringTag
不是一个内部插槽,因此具有不同标签的对象不是自动取消资格的对象,我担心拒绝任何具有这种不同标签的对象会过于禁止。但这些情况可能太少而不值得关注@@toStringTag
,因此可能会根据相关方法被拒绝1因此,本质上,我想知道
Object.prototype.toString
白名单方法是否足以避免误报或漏报,以及其他检测技术是否可以提供更精确的控制。这是Web平台包含“魔法”的不幸地方之一,即无法使用平台的其他部分(ECMAScript、浏览器API等)实现的行为。由于您没有访问这些内部插槽的权限,因此无法实现与本机实现相同的测试。一般来说,我们希望从平台上消除魔法,但是。。。有很多,而且很少是最优先的工作。。。我还没有(到目前为止?)花足够的时间研究你的算法来判断它是否“基本上足够”,所以我不会把它列为一个答案。顺便说一句,FWIW,@JoshuaBell,关于Chrome中错误的不违背承诺、WeakMap和WeakSet(SCA的第18步),我报告(但它被归类为垃圾邮件)。我刚才在评论中提到了对象的非故障。prototype
作为一个(非数组)外来对象,它似乎也应该故障。感谢ping。我将尝试反垃圾邮件的问题(我至少报告为假阳性)可能的重复