92什么意思| 酪氨酸酶是什么东西| xxl是什么尺码| 嗦是什么意思| 孕囊形态欠规则是什么意思| 软装是什么| 条件反射是什么意思| 谷维素是治疗什么的| 衣冠禽兽指什么生肖| 18k金是什么金| 叻叻猪是什么意思| 950是什么金| 什么水果可以降火| 祈祷是什么意思| 辩驳是什么意思| 元胡是什么| 梦想成真是什么意思| 什么的木筏| 画地为牢下一句是什么| 长痘痘涂什么药膏| 脸上长黑斑是什么原因引起的| 奶奶的哥哥叫什么| dm表示什么单位| 脚气长什么样| 妇科检查bv是什么意思| 毛囊炎用什么药最有效| wis是什么牌子| 维生素b6治什么病| 吃什么有饱腹感还减肥| 不劳而获是什么意思| pac是什么| 海带有什么营养| 门可罗雀什么意思| 结核抗体阴性代表什么| 哑巴是什么生肖| 梦见自己出轨是什么意思| 药敏试验是什么意思| 手突然发痒是什么原因| 程字五行属什么| 疱疹挂号挂什么科室| 头顶痛什么原因| 过敏性鼻炎吃什么药好的快| 蕈是什么意思| 女生是什么意思| 氟西汀什么意思| 总胆汁酸高是什么意思| 催供香是什么意思| 非典型鳞状细胞意义不明确是什么意思| 鼻梁有横纹是什么原因| 什么的银发| 男人是什么| 奔跑吧什么时候播出| 男人阳气不足有什么症状| 香叶是什么树叶| 为什么姨妈迟迟不来| 什么样的女人最旺夫| 什么是有机奶粉| 四楼五行属什么| 吃饭是什么意思| 肝火旺盛吃什么| 板栗不能和什么一起吃| 荔枝有什么作用与功效| 下家是什么意思| 呦西是什么意思| 呼吸道感染用什么药| 什么时候有胎心| 产后恶露吃什么排干净| 震颤是什么病| 鸡眼膏为什么越贴越疼| 陶土色大便是什么颜色| eee是什么牌子的鞋| 县级市市长什么级别| 888是什么意思| 牙疼吃什么水果好| 凝血功能障碍是什么病| 5月6号是什么星座| 缺维生素b吃什么食物| 什么情况下需要做宫腔镜| 牛牛是什么意思| vape是什么意思| 前来是什么意思| 空调买什么牌子好| 复姓什么意思| 高颜值是什么意思| 何去何从是什么意思| 占便宜是什么意思| 什么姿势舒服| 什么人容易得天疱疮| 惴惴不安什么意思| 小葫芦项链是什么牌子| 双子座和什么星座最不配| 自然流产的症状是什么样的| 七月一号是什么节| 7月13日是什么节日| 鸡皮肤是什么原因引起的| 隐翅虫咬了用什么药膏| 晚上睡觉脚底发热是什么原因| 用什么泡脚可以脸上祛斑| 三严三实是什么| 白头发多吃什么食物能变黑| 用盐水洗脸有什么效果| 申时左眼跳是什么预兆| 三点水加盆读什么| 鞘膜积液是什么病| 梦到喝酒是什么意思| 清华什么专业最好| 什么是僵尸肉| 手指甲凹凸不平是什么原因| 前列腺炎不治疗有什么后果| 数字货币是什么| 布洛芬属于什么类药物| 白细胞和淋巴细胞偏高是什么原因| 毛泽东女儿为什么姓李| 吃什么头发长得快| 新生儿满月打什么疫苗| 双子座和什么星座最不配| 异地办理护照需要什么材料| 苏武牧羊是什么意思| 手淫会导致什么疾病| 涧是什么意思| 疖肿是什么| 舌下腺囊肿挂什么科| 全科医学科是什么科| 天方夜谭是什么生肖| 长沙有什么玩的| 撸是什么意思| 难舍难分是什么意思| 圣诞礼物什么时候送| 梦见水是什么预兆| 为什么会头疼| 最小的动物是什么| 过敏性荨麻疹吃什么药| 血常规一般查什么病| 尿频尿多是什么原因| 为什么会阳痿| 吃什么治疗湿气重| 一只脚心疼是什么原因| 什么病不能吃竹笋| 保健品是什么| 反复低烧是什么原因| 新诺明又叫什么| 手掌横纹代表什么意思| 核桃什么时候成熟| 泽去掉三点水念什么| 夫妻分房睡意味着什么| 又什么又什么| 史无前例是什么意思| 水代表什么数字| 梦见胎死腹中预示什么| 肩周炎吃什么药效果最好| 腰肌劳损是什么症状| 为什么天上会下雨| 竹外桃花三两枝的下一句是什么| 上火便秘吃什么最快排便| 财主是什么意思| 肺炎吃什么药最有效| afd是什么意思| 山穷水尽的尽是什么意思| 经期有血块是什么原因| 老当益壮是什么意思| 恩客是什么意思| 车辆购置税什么时候交| 为什么手会发麻| 9月份什么星座| 猪鬃为什么是战略物资| 身份证末尾x代表什么| jerry英文名什么意思| 为什么老是做梦| 尿道炎看什么科室好| 419是什么意思| 勃不起来吃什么药| 剖腹产第三天可以吃什么| 大豆指的是什么豆| 定海神针什么意思| 纸包鸡什么意思| 什么的被子| 股票杠杆是什么意思| 秋天都有什么| 笑靥什么意思| 狗狗为什么会得细小| 快递什么时候上班| 闰月要给父母买什么| bl是什么单位| k3是什么| 北肖指什么生肖| 营养师是干什么的| 什么是梦想| dha每天什么时候吃最好| 儿童内热吃什么去内热| 昱五行属性是什么| 受精卵着床失败有什么症状| 皮试是什么| 夏天爱出汗是什么原因| 荨麻疹可以涂什么药膏| 左心室高电压是什么意思| 美眉是什么意思| 个子矮吃什么才能长高| 孙红雷的老婆叫什么名字| exo什么时候出道的| 乙肝表面抗体是什么意思| 用什么药膏能拔去粉瘤| nike是什么牌子| ryan是什么意思| 胸骨突出是什么原因| 脸上老是长闭口粉刺是什么原因| 百家姓第一个姓是什么| 尿蛋白是什么病| 8岁属什么| 三个鬼念什么| 为什么会晨勃| 属马的和什么属相不合| 安厝是什么意思| eblan是什么品牌| 宫腔内稍高回声是什么意思| 去新加坡买什么| 69年属什么生肖| 手心痒是什么原因| 梦见菊花是什么意思啊| 镀18k金是什么意思| 女人阴唇发黑是什么原因| 医院特需门诊什么意思| 牛肉不能和什么水果一起吃| av是什么| 发际线长痘痘是什么原因| 夫妻都是o型血孩子是什么血型| lbl是什么意思| 明天吃什么| 脸部痒是什么原因| 喝冰美式有什么好处| 宫腔内偏强回声是什么意思| 上午十点是什么时辰| 绿豆可以和什么一起煮| 七月属什么生肖| 人生于世上有几个知己是什么歌| 发蜡和发泥有什么区别| 秋后问斩是什么意思| 红袖什么意思| 迎春花什么时候开| 非萎缩性胃炎吃什么药| 多才多艺是什么生肖| 为什么记忆力很差| 蛤蚧是什么| 脾肾两虚吃什么中成药| 胎毒是什么样子的图片| 胃出血恢复期吃什么好| 吃什么好| 左肾尿盐结晶是什么意思| 骨质断裂是什么意思| 金蟾是什么| 中元节又叫什么节| 金色和什么颜色搭配好看| 辣椒什么时候种| 保家卫国是什么生肖| 血常规主要检查什么| 七月二十四是什么星座| 荷兰豆炒什么好吃| 想留不能留才最寂寞是什么歌| 产后复查都查什么| 奶茶里面的珍珠是什么做的| 兰州大学什么专业最好| 皮蛋吃多了有什么危害| 牙周炎用什么药| 太上皇是什么意思| 早起胃疼是什么原因导致的| 百度
    1. 2.7 Safe passing of structured data
      1. 2.7.1 Serializable objects
      2. 2.7.2 Transferable objects
      3. 2.7.3 StructuredSerializeInternal ( value, forStorage [ , memory ] )
      4. 2.7.4 StructuredSerialize ( value )
      5. 2.7.5 StructuredSerializeForStorage ( value )
      6. 2.7.6 StructuredDeserialize ( serialized, targetRealm [ , memory ] )
      7. 2.7.7 StructuredSerializeWithTransfer ( value, transferList )
      8. 2.7.8 StructuredDeserializeWithTransfer ( serializeWithTransferResult, targetRealm )
      9. 2.7.9 Performing serialization and transferring from other specifications
      10. 2.7.10 Structured cloning API

2.7 Safe passing of structured data

To support passing JavaScript objects, including platform objects, across realm boundaries, this specification defines the following infrastructure for serializing and deserializing objects, including in some cases transferring the underlying data instead of copying it. Collectively this serialization/deserialization process is known as "structured cloning", although most APIs perform separate serialization and deserialization steps. (With the notable exception being the structuredClone() method.)

This section uses the terminology and typographic conventions from the JavaScript specification. [JAVASCRIPT]

2.7.1 Serializable objects

/developer.mozilla.org/en-US/docs/Glossary/Serializable_object

Firefox103+SafariNoChrome77+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

/developer.mozilla.org/en-US/docs/Glossary/Serializable_object

Firefox103+SafariNoChrome77+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

/developer.mozilla.org/en-US/docs/Glossary/Serializable_object

Firefox103+SafariNoChrome77+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

/developer.mozilla.org/en-US/docs/Glossary/Serializable_object

Firefox103+SafariNoChrome77+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

/developer.mozilla.org/en-US/docs/Glossary/Serializable_object

Firefox103+SafariNoChrome77+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

/developer.mozilla.org/en-US/docs/Glossary/Serializable_object

Firefox103+SafariNoChrome77+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

/developer.mozilla.org/en-US/docs/Glossary/Serializable_object

Firefox103+SafariNoChrome77+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

Serializable objects support being serialized, and later deserialized, in a way that is independent of any given realm. This allows them to be stored on disk and later restored, or cloned across agent and even agent cluster boundaries.

Not all objects are serializable objects, and not all aspects of objects that are serializable objects are necessarily preserved when they are serialized.

Platform objects can be serializable objects if their primary interface is decorated with the [Serializable] IDL extended attribute. Such interfaces must also define the following algorithms:

serialization steps, taking a platform object value, a Record serialized, and a boolean forStorage

A set of steps that serializes the data in value into fields of serialized. The resulting data serialized into serialized must be independent of any realm.

These steps may throw an exception if serialization is not possible.

These steps may perform a sub-serialization to serialize nested data structures. They should not call StructuredSerialize directly, as doing so will omit the important memory argument.

The introduction of these steps should omit mention of the forStorage argument if it is not relevant to the algorithm.

deserialization steps, taking a Record serialized, a platform object value, and a realm targetRealm

A set of steps that deserializes the data in serialized, using it to set up value as appropriate. value will be a newly-created instance of the platform object type in question, with none of its internal data set up; setting that up is the job of these steps.

These steps may throw an exception if deserialization is not possible.

These steps may perform a sub-deserialization to deserialize nested data structures. They should not call StructuredDeserialize directly, as doing so will omit the important targetRealm and memory arguments.

It is up to the definition of individual platform objects to determine what data is serialized and deserialized by these steps. Typically the steps are very symmetric.

The [Serializable] extended attribute must take no arguments, and must only appear on an interface. It must not appear more than once on an interface.

For a given platform object, only the object's primary interface is considered during the (de)serialization process. Thus, if inheritance is involved in defining the interface, each [Serializable]-annotated interface in the inheritance chain needs to define standalone serialization steps and deserialization steps, including taking into account any important data that might come from inherited interfaces.

Let's say we were defining a platform object Person, which had associated with it two pieces of associated data:

We could then define Person instances to be serializable objects by annotating the Person interface with the [Serializable] extended attribute, and defining the following accompanying algorithms:

Their serialization steps, given value and serialized:

  1. Set serialized.[[Name]] to value's associated name value.

  2. Let serializedBestFriend be the sub-serialization of value's associated best friend value.

  3. Set serialized.[[BestFriend]] to serializedBestFriend.

Their deserialization steps, given serialized, value, and targetRealm:

  1. Set value's associated name value to serialized.[[Name]].

  2. Let deserializedBestFriend be the sub-deserialization of serialized.[[BestFriend]].

  3. Set value's associated best friend value to deserializedBestFriend.

Objects defined in the JavaScript specification are handled by the StructuredSerialize abstract operation directly.

Originally, this specification defined the concept of "cloneable objects", which could be cloned from one realm to another. However, to better specify the behavior of certain more complex situations, the model was updated to make the serialization and deserialization explicit.

2.7.2 Transferable objects

Transferable objects support being transferred across agents. Transferring is effectively recreating the object while sharing a reference to the underlying data and then detaching the object being transferred. This is useful to transfer ownership of expensive resources. Not all objects are transferable objects and not all aspects of objects that are transferable objects are necessarily preserved when transferred.

Transferring is an irreversible and non-idempotent operation. Once an object has been transferred, it cannot be transferred, or indeed used, again.

Platform objects can be transferable objects if their primary interface is decorated with the [Transferable] IDL extended attribute. Such interfaces must also define the following algorithms:

transfer steps, taking a platform object value and a Record dataHolder

A set of steps that transfers the data in value into fields of dataHolder. The resulting data held in dataHolder must be independent of any realm.

These steps may throw an exception if transferral is not possible.

transfer-receiving steps, taking a Record dataHolder and a platform object value

A set of steps that receives the data in dataHolder, using it to set up value as appropriate. value will be a newly-created instance of the platform object type in question, with none of its internal data set up; setting that up is the job of these steps.

These steps may throw an exception if it is not possible to receive the transfer.

It is up to the definition of individual platform objects to determine what data is transferred by these steps. Typically the steps are very symmetric.

The [Transferable] extended attribute must take no arguments, and must only appear on an interface. It must not appear more than once on an interface.

For a given platform object, only the object's primary interface is considered during the transferring process. Thus, if inheritance is involved in defining the interface, each [Transferable]-annotated interface in the inheritance chain needs to define standalone transfer steps and transfer-receiving steps, including taking into account any important data that might come from inherited interfaces.

Platform objects that are transferable objects have a [[Detached]] internal slot. This is used to ensure that once a platform object has been transferred, it cannot be transferred again.

Objects defined in the JavaScript specification are handled by the StructuredSerializeWithTransfer abstract operation directly.

2.7.3 StructuredSerializeInternal ( value, forStorage [ , memory ] )

The StructuredSerializeInternal abstract operation takes as input a JavaScript value value and serializes it to a realm-independent form, represented here as a Record. This serialized form has all the information necessary to later deserialize into a new JavaScript value in a different realm.

This process can throw an exception, for example when trying to serialize un-serializable objects.

  1. If memory was not supplied, let memory be an empty map.

    The purpose of the memory map is to avoid serializing objects twice. This ends up preserving cycles and the identity of duplicate objects in graphs.

  2. If memory[value] exists, then return memory[value].

  3. Let deep be false.

  4. If value is undefined, null, a Boolean, a Number, a BigInt, or a String, then return { [[Type]]: "primitive", [[Value]]: value }.

  5. If value is a Symbol, then throw a "DataCloneError" DOMException.

  6. Let serialized be an uninitialized value.

  7. If value has a [[BooleanData]] internal slot, then set serialized to { [[Type]]: "Boolean", [[BooleanData]]: value.[[BooleanData]] }.

  8. Otherwise, if value has a [[NumberData]] internal slot, then set serialized to { [[Type]]: "Number", [[NumberData]]: value.[[NumberData]] }.

  9. Otherwise, if value has a [[BigIntData]] internal slot, then set serialized to { [[Type]]: "BigInt", [[BigIntData]]: value.[[BigIntData]] }.

  10. Otherwise, if value has a [[StringData]] internal slot, then set serialized to { [[Type]]: "String", [[StringData]]: value.[[StringData]] }.

  11. Otherwise, if value has a [[DateValue]] internal slot, then set serialized to { [[Type]]: "Date", [[DateValue]]: value.[[DateValue]] }.

  12. Otherwise, if value has a [[RegExpMatcher]] internal slot, then set serialized to { [[Type]]: "RegExp", [[RegExpMatcher]]: value.[[RegExpMatcher]], [[OriginalSource]]: value.[[OriginalSource]], [[OriginalFlags]]: value.[[OriginalFlags]] }.

  13. Otherwise, if value has an [[ArrayBufferData]] internal slot, then:

    1. If IsSharedArrayBuffer(value) is true, then:

      1. If the current settings object's cross-origin isolated capability is false, then throw a "DataCloneError" DOMException.

        This check is only needed when serializing (and not when deserializing) as the cross-origin isolated capability cannot change over time and a SharedArrayBuffer cannot leave an agent cluster.

      2. If forStorage is true, then throw a "DataCloneError" DOMException.

      3. If value has an [[ArrayBufferMaxByteLength]] internal slot, then set serialized to { [[Type]]: "GrowableSharedArrayBuffer", [[ArrayBufferData]]: value.[[ArrayBufferData]], [[ArrayBufferByteLengthData]]: value.[[ArrayBufferByteLengthData]], [[ArrayBufferMaxByteLength]]: value.[[ArrayBufferMaxByteLength]], [[AgentCluster]]: the surrounding agent's agent cluster }.

      4. Otherwise, set serialized to { [[Type]]: "SharedArrayBuffer", [[ArrayBufferData]]: value.[[ArrayBufferData]], [[ArrayBufferByteLength]]: value.[[ArrayBufferByteLength]], [[AgentCluster]]: the surrounding agent's agent cluster }.

    2. Otherwise:

      1. If IsDetachedBuffer(value) is true, then throw a "DataCloneError" DOMException.

      2. Let size be value.[[ArrayBufferByteLength]].

      3. Let dataCopy be ? CreateByteDataBlock(size).

        This can throw a RangeError exception upon allocation failure.

      4. Perform CopyDataBlockBytes(dataCopy, 0, value.[[ArrayBufferData]], 0, size).

      5. If value has an [[ArrayBufferMaxByteLength]] internal slot, then set serialized to { [[Type]]: "ResizableArrayBuffer", [[ArrayBufferData]]: dataCopy, [[ArrayBufferByteLength]]: size, [[ArrayBufferMaxByteLength]]: value.[[ArrayBufferMaxByteLength]] }.

      6. Otherwise, set serialized to { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: dataCopy, [[ArrayBufferByteLength]]: size }.

  14. Otherwise, if value has a [[ViewedArrayBuffer]] internal slot, then:

    1. If IsArrayBufferViewOutOfBounds(value) is true, then throw a "DataCloneError" DOMException.

    2. Let buffer be the value of value's [[ViewedArrayBuffer]] internal slot.

    3. Let bufferSerialized be ? StructuredSerializeInternal(buffer, forStorage, memory).

    4. Assert: bufferSerialized.[[Type]] is "ArrayBuffer", "ResizableArrayBuffer", "SharedArrayBuffer", or "GrowableSharedArrayBuffer".

    5. If value has a [[DataView]] internal slot, then set serialized to { [[Type]]: "ArrayBufferView", [[Constructor]]: "DataView", [[ArrayBufferSerialized]]: bufferSerialized, [[ByteLength]]: value.[[ByteLength]], [[ByteOffset]]: value.[[ByteOffset]] }.

    6. Otherwise:

      1. Assert: value has a [[TypedArrayName]] internal slot.

      2. Set serialized to { [[Type]]: "ArrayBufferView", [[Constructor]]: value.[[TypedArrayName]], [[ArrayBufferSerialized]]: bufferSerialized, [[ByteLength]]: value.[[ByteLength]], [[ByteOffset]]: value.[[ByteOffset]], [[ArrayLength]]: value.[[ArrayLength]] }.

  15. Otherwise, if value has a [[MapData]] internal slot, then:

    1. Set serialized to { [[Type]]: "Map", [[MapData]]: a new empty List }.

    2. Set deep to true.

  16. Otherwise, if value has a [[SetData]] internal slot, then:

    1. Set serialized to { [[Type]]: "Set", [[SetData]]: a new empty List }.

    2. Set deep to true.

  17. Otherwise, if value has an [[ErrorData]] internal slot and value is not a platform object, then:

    1. Let name be ? Get(value, "name").

    2. If name is not one of "Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", or "URIError", then set name to "Error".

    3. Let valueMessageDesc be ? value.[[GetOwnProperty]]("message").

    4. Let message be undefined if IsDataDescriptor(valueMessageDesc) is false, and ? ToString(valueMessageDesc.[[Value]]) otherwise.

    5. Set serialized to { [[Type]]: "Error", [[Name]]: name, [[Message]]: message }.

    6. User agents should attach a serialized representation of any interesting accompanying data which are not yet specified, notably the stack property, to serialized.

      See the Error Stacks proposal for in-progress work on specifying this data. [JSERRORSTACKS]

  18. Otherwise, if value is an Array exotic object, then:

    1. Let valueLenDescriptor be ? OrdinaryGetOwnProperty(value, "length").

    2. Let valueLen be valueLenDescriptor.[[Value]].

    3. Set serialized to { [[Type]]: "Array", [[Length]]: valueLen, [[Properties]]: a new empty List }.

    4. Set deep to true.

  19. Otherwise, if value is a platform object that is a serializable object:

    1. If value has a [[Detached]] internal slot whose value is true, then throw a "DataCloneError" DOMException.

    2. Let typeString be the identifier of the primary interface of value.

    3. Set serialized to { [[Type]]: typeString }.

    4. Set deep to true.

  20. Otherwise, if value is a platform object, then throw a "DataCloneError" DOMException.

  21. Otherwise, if IsCallable(value) is true, then throw a "DataCloneError" DOMException.

  22. Otherwise, if value has any internal slot other than [[Prototype]], [[Extensible]], or [[PrivateElements]], then throw a "DataCloneError" DOMException.

    For instance, a [[PromiseState]] or [[WeakMapData]] internal slot.

  23. Otherwise, if value is an exotic object and value is not the %Object.prototype% intrinsic object associated with any realm, then throw a "DataCloneError" DOMException.

    For instance, a proxy object.

  24. Otherwise:

    1. Set serialized to { [[Type]]: "Object", [[Properties]]: a new empty List }.

    2. Set deep to true.

    %Object.prototype% will end up being handled via this step and subsequent steps. The end result is that its exoticness is ignored, and after deserialization the result will be an empty object (not an immutable prototype exotic object).

  25. Set memory[value] to serialized.

  26. If deep is true, then:

    1. If value has a [[MapData]] internal slot, then:

      1. Let copiedList be a new empty List.

      2. For each Record { [[Key]], [[Value]] } entry of value.[[MapData]]:

        1. Let copiedEntry be a new Record { [[Key]]: entry.[[Key]], [[Value]]: entry.[[Value]] }.

        2. If copiedEntry.[[Key]] is not the special value empty, append copiedEntry to copiedList.

      3. For each Record { [[Key]], [[Value]] } entry of copiedList:

        1. Let serializedKey be ? StructuredSerializeInternal(entry.[[Key]], forStorage, memory).

        2. Let serializedValue be ? StructuredSerializeInternal(entry.[[Value]], forStorage, memory).

        3. Append { [[Key]]: serializedKey, [[Value]]: serializedValue } to serialized.[[MapData]].

    2. Otherwise, if value has a [[SetData]] internal slot, then:

      1. Let copiedList be a new empty List.

      2. For each entry of value.[[SetData]]:

        1. If entry is not the special value empty, append entry to copiedList.

      3. For each entry of copiedList:

        1. Let serializedEntry be ? StructuredSerializeInternal(entry, forStorage, memory).

        2. Append serializedEntry to serialized.[[SetData]].

    3. Otherwise, if value is a platform object that is a serializable object, then perform the serialization steps for value's primary interface, given value, serialized, and forStorage.

      The serialization steps may need to perform a sub-serialization. This is an operation which takes as input a value subValue, and returns StructuredSerializeInternal(subValue, forStorage, memory). (In other words, a sub-serialization is a specialization of StructuredSerializeInternal to be consistent within this invocation.)

    4. Otherwise, for each key in ! EnumerableOwnProperties(value, key):

      1. If ! HasOwnProperty(value, key) is true, then:

        1. Let inputValue be ? value.[[Get]](key, value).

        2. Let outputValue be ? StructuredSerializeInternal(inputValue, forStorage, memory).

        3. Append { [[Key]]: key, [[Value]]: outputValue } to serialized.[[Properties]].

  27. Return serialized.

It's important to realize that the Records produced by StructuredSerializeInternal might contain "pointers" to other records that create circular references. For example, when we pass the following JavaScript object into StructuredSerializeInternal:

const o = {};
o.myself = o;

it produces the following result:

{
  [[Type]]: "Object",
  [[Properties]]: ?
    {
      [[Key]]: "myself",
      [[Value]]: <a pointer to this whole structure>
    }
  ?
}

2.7.4 StructuredSerialize ( value )

  1. Return ? StructuredSerializeInternal(value, false).

2.7.5 StructuredSerializeForStorage ( value )

  1. Return ? StructuredSerializeInternal(value, true).

2.7.6 StructuredDeserialize ( serialized, targetRealm [ , memory ] )

The StructuredDeserialize abstract operation takes as input a Record serialized, which was previously produced by StructuredSerialize or StructuredSerializeForStorage, and deserializes it into a new JavaScript value, created in targetRealm.

This process can throw an exception, for example when trying to allocate memory for the new objects (especially ArrayBuffer objects).

  1. If memory was not supplied, let memory be an empty map.

    The purpose of the memory map is to avoid deserializing objects twice. This ends up preserving cycles and the identity of duplicate objects in graphs.

  2. If memory[serialized] exists, then return memory[serialized].

  3. Let deep be false.

  4. Let value be an uninitialized value.

  5. If serialized.[[Type]] is "primitive", then set value to serialized.[[Value]].

  6. Otherwise, if serialized.[[Type]] is "Boolean", then set value to a new Boolean object in targetRealm whose [[BooleanData]] internal slot value is serialized.[[BooleanData]].

  7. Otherwise, if serialized.[[Type]] is "Number", then set value to a new Number object in targetRealm whose [[NumberData]] internal slot value is serialized.[[NumberData]].

  8. Otherwise, if serialized.[[Type]] is "BigInt", then set value to a new BigInt object in targetRealm whose [[BigIntData]] internal slot value is serialized.[[BigIntData]].

  9. Otherwise, if serialized.[[Type]] is "String", then set value to a new String object in targetRealm whose [[StringData]] internal slot value is serialized.[[StringData]].

  10. Otherwise, if serialized.[[Type]] is "Date", then set value to a new Date object in targetRealm whose [[DateValue]] internal slot value is serialized.[[DateValue]].

  11. Otherwise, if serialized.[[Type]] is "RegExp", then set value to a new RegExp object in targetRealm whose [[RegExpMatcher]] internal slot value is serialized.[[RegExpMatcher]], whose [[OriginalSource]] internal slot value is serialized.[[OriginalSource]], and whose [[OriginalFlags]] internal slot value is serialized.[[OriginalFlags]].

  12. Otherwise, if serialized.[[Type]] is "SharedArrayBuffer", then:

    1. If targetRealm's corresponding agent cluster is not serialized.[[AgentCluster]], then throw a "DataCloneError" DOMException.

    2. Otherwise, set value to a new SharedArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is serialized.[[ArrayBufferData]] and whose [[ArrayBufferByteLength]] internal slot value is serialized.[[ArrayBufferByteLength]].

  13. Otherwise, if serialized.[[Type]] is "GrowableSharedArrayBuffer", then:

    1. If targetRealm's corresponding agent cluster is not serialized.[[AgentCluster]], then throw a "DataCloneError" DOMException.

    2. Otherwise, set value to a new SharedArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is serialized.[[ArrayBufferData]], whose [[ArrayBufferByteLengthData]] internal slot value is serialized.[[ArrayBufferByteLengthData]], and whose [[ArrayBufferMaxByteLength]] internal slot value is serialized.[[ArrayBufferMaxByteLength]].

  14. Otherwise, if serialized.[[Type]] is "ArrayBuffer", then set value to a new ArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is serialized.[[ArrayBufferData]], and whose [[ArrayBufferByteLength]] internal slot value is serialized.[[ArrayBufferByteLength]].

    If this throws an exception, catch it, and then throw a "DataCloneError" DOMException.

    This step might throw an exception if there is not enough memory available to create such an ArrayBuffer object.

  15. Otherwise, if serialized.[[Type]] is "ResizableArrayBuffer", then set value to a new ArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is serialized.[[ArrayBufferData]], whose [[ArrayBufferByteLength]] internal slot value is serialized.[[ArrayBufferByteLength]], and whose [[ArrayBufferMaxByteLength]] internal slot value is serialized.[[ArrayBufferMaxByteLength]].

    If this throws an exception, catch it, and then throw a "DataCloneError" DOMException.

    This step might throw an exception if there is not enough memory available to create such an ArrayBuffer object.

  16. Otherwise, if serialized.[[Type]] is "ArrayBufferView", then:

    1. Let deserializedArrayBuffer be ? StructuredDeserialize(serialized.[[ArrayBufferSerialized]], targetRealm, memory).

    2. If serialized.[[Constructor]] is "DataView", then set value to a new DataView object in targetRealm whose [[ViewedArrayBuffer]] internal slot value is deserializedArrayBuffer, whose [[ByteLength]] internal slot value is serialized.[[ByteLength]], and whose [[ByteOffset]] internal slot value is serialized.[[ByteOffset]].

    3. Otherwise, set value to a new typed array object in targetRealm, using the constructor given by serialized.[[Constructor]], whose [[ViewedArrayBuffer]] internal slot value is deserializedArrayBuffer, whose [[TypedArrayName]] internal slot value is serialized.[[Constructor]], whose [[ByteLength]] internal slot value is serialized.[[ByteLength]], whose [[ByteOffset]] internal slot value is serialized.[[ByteOffset]], and whose [[ArrayLength]] internal slot value is serialized.[[ArrayLength]].

  17. Otherwise, if serialized.[[Type]] is "Map", then:

    1. Set value to a new Map object in targetRealm whose [[MapData]] internal slot value is a new empty List.

    2. Set deep to true.

  18. Otherwise, if serialized.[[Type]] is "Set", then:

    1. Set value to a new Set object in targetRealm whose [[SetData]] internal slot value is a new empty List.

    2. Set deep to true.

  19. Otherwise, if serialized.[[Type]] is "Array", then:

    1. Let outputProto be targetRealm.[[Intrinsics]].[[%Array.prototype%]].

    2. Set value to ! ArrayCreate(serialized.[[Length]], outputProto).

    3. Set deep to true.

  20. Otherwise, if serialized.[[Type]] is "Object", then:

    1. Set value to a new Object in targetRealm.

    2. Set deep to true.

  21. Otherwise, if serialized.[[Type]] is "Error", then:

    1. Let prototype be %Error.prototype%.

    2. If serialized.[[Name]] is "EvalError", then set prototype to %EvalError.prototype%.

    3. If serialized.[[Name]] is "RangeError", then set prototype to %RangeError.prototype%.

    4. If serialized.[[Name]] is "ReferenceError", then set prototype to %ReferenceError.prototype%.

    5. If serialized.[[Name]] is "SyntaxError", then set prototype to %SyntaxError.prototype%.

    6. If serialized.[[Name]] is "TypeError", then set prototype to %TypeError.prototype%.

    7. If serialized.[[Name]] is "URIError", then set prototype to %URIError.prototype%.

    8. Let message be serialized.[[Message]].

    9. Set value to OrdinaryObjectCreate(prototype, ? [[ErrorData]] ?).

    10. Let messageDesc be PropertyDescriptor { [[Value]]: message, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }.

    11. If message is not undefined, then perform ! OrdinaryDefineOwnProperty(value, "message", messageDesc).

    12. Any interesting accompanying data attached to serialized should be deserialized and attached to value.

  22. Otherwise:

    1. Let interfaceName be serialized.[[Type]].

    2. If the interface identified by interfaceName is not exposed in targetRealm, then throw a "DataCloneError" DOMException.

    3. Set value to a new instance of the interface identified by interfaceName, created in targetRealm.

    4. Set deep to true.

  23. Set memory[serialized] to value.

  24. If deep is true, then:

    1. If serialized.[[Type]] is "Map", then:

      1. For each Record { [[Key]], [[Value]] } entry of serialized.[[MapData]]:

        1. Let deserializedKey be ? StructuredDeserialize(entry.[[Key]], targetRealm, memory).

        2. Let deserializedValue be ? StructuredDeserialize(entry.[[Value]], targetRealm, memory).

        3. Append { [[Key]]: deserializedKey, [[Value]]: deserializedValue } to value.[[MapData]].

    2. Otherwise, if serialized.[[Type]] is "Set", then:

      1. For each entry of serialized.[[SetData]]:

        1. Let deserializedEntry be ? StructuredDeserialize(entry, targetRealm, memory).

        2. Append deserializedEntry to value.[[SetData]].

    3. Otherwise, if serialized.[[Type]] is "Array" or "Object", then:

      1. For each Record { [[Key]], [[Value]] } entry of serialized.[[Properties]]:

        1. Let deserializedValue be ? StructuredDeserialize(entry.[[Value]], targetRealm, memory).

        2. Let result be ! CreateDataProperty(value, entry.[[Key]], deserializedValue).

        3. Assert: result is true.

    4. Otherwise:

      1. Perform the appropriate deserialization steps for the interface identified by serialized.[[Type]], given serialized, value, and targetRealm.

        The deserialization steps may need to perform a sub-deserialization. This is an operation which takes as input a previously-serialized Record subSerialized, and returns StructuredDeserialize(subSerialized, targetRealm, memory). (In other words, a sub-deserialization is a specialization of StructuredDeserialize to be consistent within this invocation.)

  25. Return value.

2.7.7 StructuredSerializeWithTransfer ( value, transferList )

  1. Let memory be an empty map.

    In addition to how it is used normally by StructuredSerializeInternal, in this algorithm memory is also used to ensure that StructuredSerializeInternal ignores items in transferList, and let us do our own handling instead.

  2. For each transferable of transferList:

    1. If transferable has neither an [[ArrayBufferData]] internal slot nor a [[Detached]] internal slot, then throw a "DataCloneError" DOMException.

    2. If transferable has an [[ArrayBufferData]] internal slot and IsSharedArrayBuffer(transferable) is true, then throw a "DataCloneError" DOMException.

    3. If memory[transferable] exists, then throw a "DataCloneError" DOMException.

    4. Set memory[transferable] to { [[Type]]: an uninitialized value }.

      transferable is not transferred yet as transferring has side effects and StructuredSerializeInternal needs to be able to throw first.

  3. Let serialized be ? StructuredSerializeInternal(value, false, memory).

  4. Let transferDataHolders be a new empty List.

  5. For each transferable of transferList:

    1. If transferable has an [[ArrayBufferData]] internal slot and IsDetachedBuffer(transferable) is true, then throw a "DataCloneError" DOMException.

    2. If transferable has a [[Detached]] internal slot and transferable.[[Detached]] is true, then throw a "DataCloneError" DOMException.

    3. Let dataHolder be memory[transferable].

    4. If transferable has an [[ArrayBufferData]] internal slot, then:

      1. If transferable has an [[ArrayBufferMaxByteLength]] internal slot, then:

        1. Set dataHolder.[[Type]] to "ResizableArrayBuffer".

        2. Set dataHolder.[[ArrayBufferData]] to transferable.[[ArrayBufferData]].

        3. Set dataHolder.[[ArrayBufferByteLength]] to transferable.[[ArrayBufferByteLength]].

        4. Set dataHolder.[[ArrayBufferMaxByteLength]] to transferable.[[ArrayBufferMaxByteLength]].

      2. Otherwise:

        1. Set dataHolder.[[Type]] to "ArrayBuffer".

        2. Set dataHolder.[[ArrayBufferData]] to transferable.[[ArrayBufferData]].

        3. Set dataHolder.[[ArrayBufferByteLength]] to transferable.[[ArrayBufferByteLength]].

      3. Perform ? DetachArrayBuffer(transferable).

        Specifications can use the [[ArrayBufferDetachKey]] internal slot to prevent ArrayBuffers from being detached. This is used in WebAssembly JavaScript Interface, for example. [WASMJS]

    5. Otherwise:

      1. Assert: transferable is a platform object that is a transferable object.

      2. Let interfaceName be the identifier of the primary interface of transferable.

      3. Set dataHolder.[[Type]] to interfaceName.

      4. Perform the appropriate transfer steps for the interface identified by interfaceName, given transferable and dataHolder.

      5. Set transferable.[[Detached]] to true.

    6. Append dataHolder to transferDataHolders.

  6. Return { [[Serialized]]: serialized, [[TransferDataHolders]]: transferDataHolders }.

2.7.8 StructuredDeserializeWithTransfer ( serializeWithTransferResult, targetRealm )

  1. Let memory be an empty map.

    Analogous to StructuredSerializeWithTransfer, in addition to how it is used normally by StructuredDeserialize, in this algorithm memory is also used to ensure that StructuredDeserialize ignores items in serializeWithTransferResult.[[TransferDataHolders]], and let us do our own handling instead.

  2. Let transferredValues be a new empty List.

  3. For each transferDataHolder of serializeWithTransferResult.[[TransferDataHolders]]:

    1. Let value be an uninitialized value.

    2. If transferDataHolder.[[Type]] is "ArrayBuffer", then set value to a new ArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is transferDataHolder.[[ArrayBufferData]], and whose [[ArrayBufferByteLength]] internal slot value is transferDataHolder.[[ArrayBufferByteLength]].

      In cases where the original memory occupied by [[ArrayBufferData]] is accessible during the deserialization, this step is unlikely to throw an exception, as no new memory needs to be allocated: the memory occupied by [[ArrayBufferData]] is instead just getting transferred into the new ArrayBuffer. This could be true, for example, when both the source and target realms are in the same process.

    3. Otherwise, if transferDataHolder.[[Type]] is "ResizableArrayBuffer", then set value to a new ArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is transferDataHolder.[[ArrayBufferData]], whose [[ArrayBufferByteLength]] internal slot value is transferDataHolder.[[ArrayBufferByteLength]], and whose [[ArrayBufferMaxByteLength]] internal slot value is transferDataHolder.[[ArrayBufferMaxByteLength]].

      For the same reason as the previous step, this step is also unlikely to throw an exception.

    4. Otherwise:

      1. Let interfaceName be transferDataHolder.[[Type]].

      2. If the interface identified by interfaceName is not exposed in targetRealm, then throw a "DataCloneError" DOMException.

      3. Set value to a new instance of the interface identified by interfaceName, created in targetRealm.

      4. Perform the appropriate transfer-receiving steps for the interface identified by interfaceName given transferDataHolder and value.

    5. Set memory[transferDataHolder] to value.

    6. Append value to transferredValues.

  4. Let deserialized be ? StructuredDeserialize(serializeWithTransferResult.[[Serialized]], targetRealm, memory).

  5. Return { [[Deserialized]]: deserialized, [[TransferredValues]]: transferredValues }.

2.7.9 Performing serialization and transferring from other specifications

Other specifications may use the abstract operations defined here. The following provides some guidance on when each abstract operation is typically useful, with examples.

StructuredSerializeWithTransfer
StructuredDeserializeWithTransfer

Cloning a value to another realm, with a transfer list, but where the target realm is not known ahead of time. In this case the serialization step can be performed immediately, with the deserialization step delayed until the target realm becomes known.

messagePort.postMessage() uses this pair of abstract operations, as the destination realm is not known until the MessagePort has been shipped.

StructuredSerialize
StructuredSerializeForStorage
StructuredDeserialize

Creating a realm-independent snapshot of a given value which can be saved for an indefinite amount of time, and then reified back into a JavaScript value later, possibly multiple times.

StructuredSerializeForStorage can be used for situations where the serialization is anticipated to be stored in a persistent manner, instead of passed between realms. It throws when attempting to serialize SharedArrayBuffer objects, since storing shared memory does not make sense. Similarly, it can throw or possibly have different behavior when given a platform object with custom serialization steps when the forStorage argument is true.

history.pushState() and history.replaceState() use StructuredSerializeForStorage on author-supplied state objects, storing them as serialized state in the appropriate session history entry. Then, StructuredDeserialize is used so that the history.state property can return a clone of the originally-supplied state object.

broadcastChannel.postMessage() uses StructuredSerialize on its input, then uses StructuredDeserialize multiple times on the result to produce a fresh clone for each destination being broadcast to. Note that transferring does not make sense in multi-destination situations.

Any API for persisting JavaScript values to the filesystem would also use StructuredSerializeForStorage on its input and StructuredDeserialize on its output.

In general, call sites may pass in Web IDL values instead of JavaScript values; this is to be understood to perform an implicit conversion to the JavaScript value before invoking these algorithms.


Call sites that are not invoked as a result of author code synchronously calling into a user agent method must take care to properly prepare to run script and prepare to run a callback before invoking StructuredSerialize, StructuredSerializeForStorage, or StructuredSerializeWithTransfer abstract operations, if they are being performed on arbitrary objects. This is necessary because the serialization process can invoke author-defined accessors as part of its final deep-serialization steps, and these accessors could call into operations that rely on the entry and incumbent concepts being properly set up.

window.postMessage() performs StructuredSerializeWithTransfer on its arguments, but is careful to do so immediately, inside the synchronous portion of its algorithm. Thus it is able to use the algorithms without needing to prepare to run script and prepare to run a callback.

In contrast, a hypothetical API that used StructuredSerialize to serialize some author-supplied object periodically, directly from a task on the event loop, would need to ensure it performs the appropriate preparations beforehand. As of this time, we know of no such APIs on the platform; usually it is simpler to perform the serialization ahead of time, as a synchronous consequence of author code.

2.7.10 Structured cloning API

result = self.structuredClone(value[, { transfer }])

Takes the input value and returns a deep copy by performing the structured clone algorithm. Transferable objects listed in the transfer array are transferred, not just cloned, meaning that they are no longer usable in the input value.

Throws a "DataCloneError" DOMException if any part of the input value is not serializable.

structuredClone

Support in all current engines.

Firefox94+Safari15.4+Chrome98+
Opera?Edge98+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

The structuredClone(value, options) method steps are:

  1. Let serialized be ? StructuredSerializeWithTransfer(value, options["transfer"]).

  2. Let deserializeRecord be ? StructuredDeserializeWithTransfer(serialized, this's relevant realm).

  3. Return deserializeRecord.[[Deserialized]].

百度