Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

Revision 778993 of The structured clone algorithm

  • Revision slug: Web/Guide/API/DOM/The_structured_clone_algorithm
  • Revision title: The structured clone algorithm
  • Revision id: 778993
  • Created:
  • Creator: abroz
  • Is current revision? No
  • Comment Deep copy code snippet didn't work.

Revision Content

The structured clone algorithm is a new algorithm defined by the HTML5 specification for serializing complex JavaScript objects. It's more capable than JSON in that it supports the serialization of objects that contain cyclic graphs — objects can refer to objects that refer to other objects in the same graph. In addition, in some cases, the structured clone algorithm may be more efficient than JSON.

The algorithm, in essence, walks over all the fields of the original object, duplicating the values of each field into a new object. If a field is, itself, an object with fields, those fields are walked over recursively until every field and sub-field is duplicated into the new object.

Benefits over JSON

There are a few key benefits of the structured clone algorithm over JSON:

  • Structured clones can duplicate RegExp objects.
  • Structured clones can duplicate {{ domxref("Blob") }}, {{ domxref("File") }}, and {{ domxref("FileList") }} objects.
  • Structured clones can duplicate {{ domxref("ImageData") }} objects. The dimensions of the clone's {{ domxref("CanvasPixelArray") }} will match the original and have a duplicate of the same pixel data.
  • Structured clones can correctly duplicate objects containing cyclic graphs of references.

Things that don't work with structured clones

  • Error and Function objects cannot be duplicated by the structured clone algorithm; attempting to do so will throw a DATA_CLONE_ERR exception.
  • Attempting to clone DOM nodes will likewise throw a DATA_CLONE_ERR exception.
  • Certain parameters of objects are not preserved:
    • The lastIndex field of RegExp objects is not preserved.
    • Property descriptors, setters, and getters (as well as similar metadata-like features) are not duplicated. For example, if an object is marked read-only using a property descriptor, it will be read-write in the duplicate, since that's the default condition.
    • The prototype chain does not get walked and duplicated.

Supported types

Object type Notes
All primitive types However not symbols
Boolean object  
String object  
Date  
RegExp The lastIndex field is not preserved.
{{ domxref("Blob") }}  
{{ domxref("File") }}  
{{ domxref("FileList") }}  
ArrayBuffer  
ArrayBufferView This basically means all typed arrays like Int32Array etc.
{{ domxref("ImageData") }}  
Array  
Object This just includes plain objects (e.g. from object literals)
Map  
Set  

Another way: deep copy‎

If you want a deep copy of an object (that is, a recursive copy of all nested properties, walking the prototype chain), you must use another approach. The following is a possible example.

function clone(objectToBeCloned) {
  var objectClone; // Cloned object, constructor of clones.
  
  // Basis.
  if (objectToBeCloned === null || !(objectToBeCloned instanceof Object)) {
    return objectToBeCloned;
  }
  
  // Filter out special objects.
  switch (objectToBeCloned.constructor) {
    // Implement other special objects here.
    case RegExp:
      objectClone = new fConstr(objectToBeCloned);
      break;
    case Date:
      objectClone = new fConstr(objectToBeCloned.getTime());
      break;
    default:
      objectClone = new fConstr();
  }
  
  // Clone each property.
  for (var prop in objectToBeCloned) {
    objectClone[prop] = clone(objectToBeCloned[prop]);
  }
  
  return objectClone;
}
  Note: This algorithm actually implements only RegExp, Array, and Date special objects. You can implement other special cases depending on your needs.

See also

Revision Source

<p>The structured clone algorithm is a new algorithm <a class="external" href="https://www.w3.org/html/wg/drafts/html/master/infrastructure.html#safe-passing-of-structured-data" title="https://www.w3.org/TR/html5/common-dom-interfaces.html#safe-passing-of-structured-data">defined by the HTML5 specification</a> for serializing complex JavaScript objects. It's more capable than <a href="/en/JSON" title="en/JSON">JSON</a>&nbsp;in that it supports the serialization of objects that contain cyclic graphs — objects can refer to objects that refer to other objects in the same graph. In addition, in some cases, the structured clone algorithm may be more efficient than JSON.</p>

<p>The algorithm, in essence, walks over all the fields of the original object, duplicating the values of each field into a new object. If a field is, itself, an object with fields, those fields are walked over recursively until every field and sub-field is duplicated into the new object.</p>

<h2 id="Benefits_over_JSON">Benefits over JSON</h2>

<p>There are a few key benefits of the structured clone algorithm over JSON:</p>

<ul>
 <li>Structured clones can duplicate <a href="/en/JavaScript/Reference/Global_Objects/RegExp" title="en/JavaScript/Reference/Global Objects/regexp"><code>RegExp</code></a> objects.</li>
 <li>Structured clones can duplicate {{ domxref("Blob") }}, {{ domxref("File") }}, and {{ domxref("FileList") }} objects.</li>
 <li>Structured clones can duplicate {{ domxref("ImageData") }} objects. The dimensions of the clone's {{ domxref("CanvasPixelArray") }} will match the original and have a duplicate of the same pixel data.</li>
 <li>Structured clones can correctly duplicate objects containing cyclic graphs of references.</li>
</ul>

<h2 id="Things_that_don't_work_with_structured_clones">Things that don't work with structured clones</h2>

<ul>
 <li><a href="/en/JavaScript/Reference/Global_Objects/Error" title="en/JavaScript/Reference/Global Objects/Error"><code>Error</code></a> and <a href="/en/JavaScript/Reference/Global_Objects/Function" title="en/JavaScript/Reference/Global Objects/Function"><code>Function</code></a> objects cannot be duplicated by the structured clone algorithm; attempting to do so will throw a <code>DATA_CLONE_ERR</code>&nbsp;exception.</li>
 <li>Attempting to clone DOM&nbsp;nodes will likewise throw a <code>DATA_CLONE_ERR</code>&nbsp;exception.</li>
 <li>Certain parameters of objects are not preserved:
  <ul>
   <li>The <code>lastIndex</code> field of <a href="/en/JavaScript/Reference/Global_Objects/RegExp" title="en/JavaScript/Reference/Global Objects/regexp"><code>RegExp</code></a> objects is not preserved.</li>
   <li>Property descriptors, setters, and getters (as well as similar metadata-like features)&nbsp;are not duplicated. For example, if an object is marked read-only using a property descriptor, it will be read-write in the duplicate, since that's the default condition.</li>
   <li>The prototype chain does not get walked and duplicated.</li>
  </ul>
 </li>
</ul>

<h2 id="Supported_types">Supported types</h2>

<table class="standard-table">
 <thead>
  <tr>
   <th scope="col">Object type</th>
   <th scope="col">Notes</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td><a href="/en-US/docs/Web/JavaScript/Data_structures#Primitive_values">All primitive types</a></td>
   <td>However not symbols</td>
  </tr>
  <tr>
   <td><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean">Boolean</a> object</td>
   <td>&nbsp;</td>
  </tr>
  <tr>
   <td>String object</td>
   <td>&nbsp;</td>
  </tr>
  <tr>
   <td><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date">Date</a></td>
   <td>&nbsp;</td>
  </tr>
  <tr>
   <td><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp">RegExp</a></td>
   <td>The <code>lastIndex</code> field is not preserved.</td>
  </tr>
  <tr>
   <td>{{ domxref("Blob") }}</td>
   <td>&nbsp;</td>
  </tr>
  <tr>
   <td>{{ domxref("File") }}</td>
   <td>&nbsp;</td>
  </tr>
  <tr>
   <td>{{ domxref("FileList") }}</td>
   <td>&nbsp;</td>
  </tr>
  <tr>
   <td><a href="/en-US/docs/Web/API/ArrayBuffer">ArrayBuffer</a></td>
   <td>&nbsp;</td>
  </tr>
  <tr>
   <td><a href="/en-US/docs/Web/API/ArrayBufferView">ArrayBufferView</a></td>
   <td>This basically means all <a href="/en-US/docs/Web/JavaScript/Typed_arrays">typed arrays</a> like Int32Array etc.</td>
  </tr>
  <tr>
   <td>{{ domxref("ImageData") }}</td>
   <td>&nbsp;</td>
  </tr>
  <tr>
   <td><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a></td>
   <td>&nbsp;</td>
  </tr>
  <tr>
   <td><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object">Object</a></td>
   <td>This just includes plain objects (e.g. from object literals)</td>
  </tr>
  <tr>
   <td><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map">Map</a></td>
   <td>&nbsp;</td>
  </tr>
  <tr>
   <td><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set">Set</a></td>
   <td>&nbsp;</td>
  </tr>
 </tbody>
</table>

<h2 id="Another_way.3A_deep_copy.E2.80.8E">Another way: deep copy‎</h2>

<p>If you want a <strong>deep copy</strong> of an object (that is, a recursive copy of all nested properties, walking the prototype chain), you must use another approach. The following is a possible example.</p>

<pre class="brush: js">
function clone(objectToBeCloned) {
  var objectClone; // Cloned object, constructor of clones.
  
  // Basis.
  if (objectToBeCloned === null || !(objectToBeCloned instanceof Object)) {
    return objectToBeCloned;
  }
  
  // Filter out special objects.
  switch (objectToBeCloned.constructor) {
    // Implement other special objects here.
    case RegExp:
      objectClone = new fConstr(objectToBeCloned);
      break;
    case Date:
      objectClone = new fConstr(objectToBeCloned.getTime());
      break;
    default:
      objectClone = new fConstr();
  }
  
  // Clone each property.
  for (var prop in objectToBeCloned) {
    objectClone[prop] = clone(objectToBeCloned[prop]);
  }
  
  return objectClone;
}
</pre>

<div class="note"><strong>&nbsp; Note:</strong> This algorithm actually implements only <a href="/en/JavaScript/Reference/Global_Objects/RegExp" title="RegExp"><code>RegExp</code></a>, <a href="/en/JavaScript/Reference/Global_Objects/Array" title="Array"><code>Array</code></a>, and <a href="/en/JavaScript/Reference/Global_Objects/Date" title="Date"><code>Date</code></a> special objects. You can implement other special cases depending on your needs.</div>

<h2 id="See_also">See also</h2>

<ul>
 <li><a class="external" href="https://www.w3.org/TR/html5/infrastructure.html#safe-passing-of-structured-data" title="https://www.w3.org/TR/html5/common-dom-interfaces.html#safe-passing-of-structured-data">HTML5 Specification:&nbsp;Safe passing of structured data</a></li>
 <li>{{ domxref("window.history") }}</li>
 <li>{{ domxref("window.postMessage()") }}</li>
 <li>{{domxref("Web Workers","Web_Workers_API")}}</li>
 <li><a href="/en-US/docs/Components.utils.cloneInto">Components.utils.cloneInto</a></li>
</ul>
Revert to this revision