The structured clone algorithm

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; that is, 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 Blob, File, and FileList objects.
  • Structured clones can duplicate ImageData objects. The dimensions of the clone's CanvasPixelArray matches the original, and has 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.

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 (arg) {
  var cln; // cloned object, constructor of clones
  if (arg === null || !(arg instanceof Object)) { return arg; } // parameters guard
  
  // Filter out special objects, and 
  constr = arg.constructor;
  RegExp === constr  && (cln = new constr(arg.source, "g".substr(0, Number(arg.global)) + "i".substr(0, Number(arg.ignoreCase)) + "m".substr(0, Number(arg.multiline))));
  Date === constr  && (cln = new constr(arg.getTime()));
  cln || (cln = new constr()); // default
  
  for
}
function copyOwnProperties (target, arg) {
  var key;
  for (key in arg) {
    if (arg.hasOwnProperty(key)) {
      target[key] = arg[key];
    }
  }
  return target;
}

  switch (constr) {
    // implement other special objects here!
    case RegExp:
      /*
      oClone = new fConstr(oToBeCloned.source, Array.prototype.filter.call("gim", function () {
        return (oToBeCloned.global | oToBeCloned.ignoreCase << 1 | oToBeCloned.multiline) & 1 << arguments[1];
      }).join(""));
      */
      oClone = new fConstr(oToBeCloned.source, "g".substr(0, Number(oToBeCloned.global)) + "i".substr(0, Number(oToBeCloned.ignoreCase)) + "m".substr(0, Number(oToBeCloned.multiline)));
      break;
    case Date:
      oClone = new fConstr(oToBeCloned.getTime());
      break;
    // etc.
    default:
      oClone = new fConstr();
  }
  for (var sProp in oToBeCloned) { oClone[sProp] = clone(oToBeCloned[sProp]); }
  return oClone;
}
Note: This algorithm actually implements only RegExp, Array, and Date special objects. You can implement other special cases depending on your needs.

See also

Document Tags and Contributors

Contributors to this page: Sheppy, Jeremie, kscarfone, rk17, fusionchess, teoli, secoif, kevmoo
Last updated by: rk17,