javascript - without - typescript object assign




Qual è il modo più efficace per clonare in profondità un oggetto in JavaScript? (20)

Qual è il modo più efficace per clonare un oggetto JavaScript? Ho visto obj = eval(uneval(o)); in uso, ma non è standard e supportato solo da Firefox .

Ho fatto cose come obj = JSON.parse(JSON.stringify(o)); ma dubita dell'efficienza.

Ho anche visto funzioni di copia ricorsiva con vari difetti.
Sono sorpreso che non esista alcuna soluzione canonica.


Nota: questa è una risposta ad un'altra risposta, non una risposta adeguata a questa domanda. Se desideri avere una clonazione veloce dell'oggetto, segui il consiglio di Corban nella risposta a questa domanda.

Voglio notare che il metodo .clone() in jQuery clona solo elementi DOM. Per clonare oggetti JavaScript, dovresti fare:

// Shallow copy
var newObject = jQuery.extend({}, oldObject);

// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);

Ulteriori informazioni possono essere trovate nella documentazione di jQuery .

Voglio anche notare che la copia profonda è in realtà molto più intelligente di quanto mostrato sopra: è in grado di evitare molte trappole (cercando di estendere in profondità un elemento DOM, ad esempio). È usato frequentemente nel core jQuery e nei plugin con grande effetto.


Clonazione strutturata

HTML5 definisce un algoritmo di clonazione interno "strutturato" che può creare cloni profondi di oggetti. È ancora limitato a determinati tipi built-in, ma oltre ai pochi tipi supportati da JSON supporta anche Date, RegExps, Maps, Sets, Blob, FileLists, ImageDatas, array sparsi, matrici tipizzate e probabilmente più in futuro . Conserva anche i riferimenti all'interno dei dati clonati, permettendogli di supportare strutture cicliche e ricorsive che causerebbero errori per JSON.

Supporto diretto nei browser: in arrivo? 🙂

I browser non forniscono attualmente un'interfaccia diretta per l'algoritmo di clonazione strutturata, ma una funzione structuredClone() globaleClone structuredClone() viene attivamente discussa in whatwg / html # 793 su GitHub e potrebbe essere in arrivo! Come attualmente proposto, utilizzarlo per la maggior parte degli scopi sarà semplice come:

const clone = structuredClone(original);

Fino a quando questo viene spedito, le implementazioni clone strutturate dei browser sono esposte solo indirettamente.

Soluzione asincrona: utilizzabile. 😕

Il modo più basso di creare un clone strutturato con le API esistenti è di pubblicare i dati attraverso una porta di un MessageChannels . L'altra porta emetterà un evento message con un clone strutturato del .data allegato. Sfortunatamente, ascoltare questi eventi è necessariamente asincrono e le alternative sincrone sono meno pratiche.

class StructuredCloner {
  constructor() {
    this.pendingClones_ = new Map();
    this.nextKey_ = 0;

    const channel = new MessageChannel();
    this.inPort_ = channel.port1;
    this.outPort_ = channel.port2;

    this.outPort_.onmessage = ({data: {key, value}}) => {
      const resolve = this.pendingClones_.get(key);
      resolve(value);
      this.pendingClones_.delete(key);
    };
    this.outPort_.start();
  }

  cloneAsync(value) {
    return new Promise(resolve => {
      const key = this.nextKey_++;
      this.pendingClones_.set(key, resolve);
      this.inPort_.postMessage({key, value});
    });
  }
}

const structuredCloneAsync = window.structuredCloneAsync =
    StructuredCloner.prototype.cloneAsync.bind(new StructuredCloner);

Esempio di utilizzo:

const main = async () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = await structuredCloneAsync(original);

  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));

  console.log("Assertions complete.");
};

main();

Soluzioni alternative sincrone: terribile! 🤢

Non ci sono buone opzioni per creare cloni strutturati in modo sincrono. Ecco invece un paio di hack poco pratici.

history.pushState() e history.replaceState() creano entrambi un clone strutturato del loro primo argomento e assegnano quel valore a history.state . Puoi usarlo per creare un clone strutturato di qualsiasi oggetto come questo:

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

Esempio di utilizzo:

'use strict';

const main = () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = structuredClone(original);
  
  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

main();

Sebbene sincrono, può essere estremamente lento. Esso incorre in tutto il sovraccarico associato alla manipolazione della cronologia del browser. La chiamata ripetuta di questo metodo può causare la mancata risposta temporanea di Chrome.

Il costruttore Notification crea un clone strutturato dei dati associati. Tenta anche di visualizzare una notifica del browser all'utente, ma questo fallirà silenziosamente a meno che tu non abbia richiesto il permesso di notifica. Nel caso in cui tu abbia il permesso per altri scopi, chiuderemo immediatamente la notifica che abbiamo creato.

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.onshow = n.close.bind(n);
  return n.data;
};

Esempio di utilizzo:

'use strict';

const main = () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = structuredClone(original);
  
  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.close();
  return n.data;
};

main();


AngularJS

Beh, se stai usando angolare puoi farlo anche tu

var newObject = angular.copy(oldObject);

C'è una biblioteca (chiamata "clone") , che funziona abbastanza bene. Fornisce la clonazione / copia ricorsiva più completa di oggetti arbitrari che io conosca. Supporta anche riferimenti circolari, che non sono ancora coperti dalle altre risposte.

Lo puoi trovare anche su npm . Può essere utilizzato per il browser e Node.js.

Ecco un esempio su come usarlo:

Installalo con

npm install clone

o confezionarlo con Ender .

ender build clone [...]

Puoi anche scaricare il codice sorgente manualmente.

Quindi puoi usarlo nel tuo codice sorgente.

var clone = require('clone');

var a = { foo: { bar: 'baz' } };  // inital value of a
var b = clone(a);                 // clone a -> b
a.foo.bar = 'foo';                // change a

console.log(a);                   // { foo: { bar: 'foo' } }
console.log(b);                   // { foo: { bar: 'baz' } }

(Disclaimer: sono l'autore della biblioteca.)


Ecco una versione della risposta di ConroyP sopra che funziona anche se il costruttore ha richiesto i parametri:

//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
    object_create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

function deepCopy(obj) {
    if(obj == null || typeof(obj) !== 'object'){
        return obj;
    }
    //make sure the returned object has the same prototype as the original
    var ret = object_create(obj.constructor.prototype);
    for(var key in obj){
        ret[key] = deepCopy(obj[key]);
    }
    return ret;
}

Questa funzione è disponibile anche nella mia libreria simpleoo .

Modificare:

Ecco una versione più robusta (grazie a Justin McCandless questo ora supporta anche i riferimenti ciclici):

/**
 * Deep copy an object (make copies of all its object properties, sub-properties, etc.)
 * An improved version of http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
 * that doesn't break if the constructor has required parameters
 * 
 * It also borrows some code from http://.com/a/11621004/560114
 */ 
function deepCopy(src, /* INTERNAL */ _visited, _copiesVisited) {
    if(src === null || typeof(src) !== 'object'){
        return src;
    }

    //Honor native/custom clone methods
    if(typeof src.clone == 'function'){
        return src.clone(true);
    }

    //Special cases:
    //Date
    if(src instanceof Date){
        return new Date(src.getTime());
    }
    //RegExp
    if(src instanceof RegExp){
        return new RegExp(src);
    }
    //DOM Element
    if(src.nodeType && typeof src.cloneNode == 'function'){
        return src.cloneNode(true);
    }

    // Initialize the visited objects arrays if needed.
    // This is used to detect cyclic references.
    if (_visited === undefined){
        _visited = [];
        _copiesVisited = [];
    }

    // Check if this object has already been visited
    var i, len = _visited.length;
    for (i = 0; i < len; i++) {
        // If so, get the copy we already made
        if (src === _visited[i]) {
            return _copiesVisited[i];
        }
    }

    //Array
    if (Object.prototype.toString.call(src) == '[object Array]') {
        //[].slice() by itself would soft clone
        var ret = src.slice();

        //add it to the visited array
        _visited.push(src);
        _copiesVisited.push(ret);

        var i = ret.length;
        while (i--) {
            ret[i] = deepCopy(ret[i], _visited, _copiesVisited);
        }
        return ret;
    }

    //If we've reached here, we have a regular object

    //make sure the returned object has the same prototype as the original
    var proto = (Object.getPrototypeOf ? Object.getPrototypeOf(src): src.__proto__);
    if (!proto) {
        proto = src.constructor.prototype; //this line would probably only be reached by very old browsers 
    }
    var dest = object_create(proto);

    //add this object to the visited array
    _visited.push(src);
    _copiesVisited.push(dest);

    for (var key in src) {
        //Note: this does NOT preserve ES5 property attributes like 'writable', 'enumerable', etc.
        //For an example of how this could be modified to do so, see the singleMixin() function
        dest[key] = deepCopy(src[key], _visited, _copiesVisited);
    }
    return dest;
}

//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
    object_create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

Leggi questo benchmark: http://jsben.ch/#/bWfk9

Nei miei precedenti test in cui la velocità era una preoccupazione principale che ho trovato

JSON.parse(JSON.stringify(obj))

essere il modo più veloce per clonare in profondità un oggetto (batte jQuery.extend con deep flag impostato su true del 10-20%).

jQuery.extend è piuttosto veloce quando il flag deep è impostato su false (clone poco profondo). È una buona opzione, perché include alcune logiche extra per la convalida del tipo e non copia su proprietà non definite, ecc., Ma anche questo rallenterà un po '.

Se si conosce la struttura degli oggetti che si sta tentando di clonare o si possono evitare array deep nested, è possibile scrivere un ciclo semplice for (var i in obj) per clonare l'oggetto mentre si controlla hasOwnProperty e sarà molto più veloce di jQuery.

Infine, se si sta tentando di clonare una struttura di oggetti noti in un ciclo caldo, è possibile ottenere MOLTO MOLTO ALTRO PERFORMANCE semplicemente inserendo la procedura clone e costruendo manualmente l'oggetto.

I motori di tracciamento JavaScript succhiano all'ottimizzazione for..in loop e controllando hasOwnProperty rallenteranno anche voi. Clone manuale quando la velocità è assoluta.

var clonedObject = {
  knownProp: obj.knownProp,
  ..
}

JSON.parse(JSON.stringify(obj)) attenzione all'utilizzo del JSON.parse(JSON.stringify(obj)) sugli oggetti Date - JSON.stringify(new Date()) restituisce una rappresentazione in formato stringa della data in formato ISO, che JSON.parse() non converte indietro a un oggetto Date . Vedi questa risposta per maggiori dettagli .

Inoltre, tieni presente che, almeno in Chrome 65, la clonazione nativa non è la strada da percorrere. Secondo questo JSPerf , l'esecuzione della clonazione nativa con la creazione di una nuova funzione è quasi 800 volte più lenta rispetto all'utilizzo di JSON.stringify, che è incredibilmente veloce su tutta la linea.


Se lo stai usando, la libreria Underscore.js ha un metodo clone .

var newObject = _.clone(oldObject);

Se non ce n'era uno integrato, potresti provare:

function clone(obj) {
    if (obj === null || typeof (obj) !== 'object' || 'isActiveClone' in obj)
        return obj;

    if (obj instanceof Date)
        var temp = new obj.constructor(); //or new Date(obj);
    else
        var temp = obj.constructor();

    for (var key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            obj['isActiveClone'] = null;
            temp[key] = clone(obj[key]);
            delete obj['isActiveClone'];
        }
    }
    return temp;
}

Supponendo che tu abbia solo variabili e non funzioni nel tuo oggetto, puoi semplicemente usare:

var newObject = JSON.parse(JSON.stringify(oldObject));

Cloning un oggetto era sempre una preoccupazione in JS, ma era tutto prima di ES6, elencherò diversi modi di copiare un oggetto in JavaScript qui sotto, immagina di avere l'oggetto sotto e vorrei avere una copia profonda di quello:

var obj = {a:1, b:2, c:3, d:4};

Ci sono alcuni modi per copiare questo oggetto, senza cambiare l'origine:

1) ES5 +, usando una semplice funzione per fare la copia per te:

function deepCopyObj(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = cloneSO(obj[i]);
        }
        return copy;
    }
    if (obj instanceof Object) {
        var copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]);
        }
        return copy;
    }
    throw new Error("Unable to copy obj this object.");
}

2) ES5 +, utilizzando JSON.parse e JSON.stringify.

var  deepCopyObj = JSON.parse(JSON.stringify(obj));

3) AngularJs:

var  deepCopyObj = angular.copy(obj);

4) jQuery:

var deepCopyObj = jQuery.extend(true, {}, obj);

5) UnderscoreJs e Loadash:

var deepCopyObj = _.cloneDeep(obj); //latest version UndescoreJs makes shallow copy

Spero che questi aiuti ...


Copia profonda degli oggetti in JavaScript (penso sia la migliore e la più semplice)

1. Utilizzo di JSON.parse (JSON.stringify (oggetto));

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}
var newObj = JSON.parse(JSON.stringify(obj));
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

2. Utilizzando il metodo creato

function cloneObject(obj) {
    var clone = {};
    for(var i in obj) {
        if(obj[i] != null &&  typeof(obj[i])=="object")
            clone[i] = cloneObject(obj[i]);
        else
            clone[i] = obj[i];
    }
    return clone;
}

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}
var newObj = cloneObject(obj);
obj.b.c = 20;

console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

3. Usando il link lodash di _.cloneDeep di Lo-Dashlodash

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = _.cloneDeep(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

4. Utilizzo del metodo Object.assign ()

var obj = { 
  a: 1,
  b: 2
}

var newObj = _.clone(obj);
obj.b = 20;
console.log(obj); // { a: 1, b: 20 }
console.log(newObj); // { a: 1, b: 2 }  

MA SBAGLIATO QUANDO

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = Object.assign({}, obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 20 } } --> WRONG
// Note: Properties on the prototype chain and non-enumerable properties cannot be copied.

5.Usando Underscore.js _.clone link Underscore.js

var obj = { 
  a: 1,
  b: 2
}

var newObj = _.clone(obj);
obj.b = 20;
console.log(obj); // { a: 1, b: 20 }
console.log(newObj); // { a: 1, b: 2 }  

MA SBAGLIATO QUANDO

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = _.cloneDeep(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 20 } } --> WRONG
// (Create a shallow-copied clone of the provided plain object. Any nested objects or arrays will be copied by reference, not duplicated.)

Media di riferimento

JSBEN.CH Performance Benchmarking Playground 1 ~ 3 http://jsben.ch/KVQLd


Crockford suggerisce (e preferisco) l'uso di questa funzione:

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

var newObject = object(oldObject);

È conciso, funziona come previsto e non hai bisogno di una biblioteca.

MODIFICARE:

Questo è un polyfill per Object.create, quindi puoi usare anche questo.

var newObject = Object.create(oldObject);

NOTA: se ne usi una parte, potresti avere problemi con alcune iterazioni che usano hasOwnProperty. Perché, createcrea un nuovo oggetto vuoto che eredita oldObject. Ma è ancora utile e pratico per la clonazione di oggetti.

Ad esempio se oldObject.a = 5;

newObject.a; // is 5

ma:

oldObject.hasOwnProperty(a); // is true
newObject.hasOwnProperty(a); // is false

Copia superficiale singola ( ECMAScript 5a edizione ):

var origin = { foo : {} };
var copy = Object.keys(origin).reduce(function(c,k){c[k]=origin[k];return c;},{});

console.log(origin, copy);
console.log(origin == copy); // false
console.log(origin.foo == copy.foo); // true

E copy-one-liner poco profondo ( ECMAScript 6a edizione , 2015):

var origin = { foo : {} };
var copy = Object.assign({}, origin);

console.log(origin, copy);
console.log(origin == copy); // false
console.log(origin.foo == copy.foo); // true

Ecco un metodo clone () completo che può clonare qualsiasi oggetto JavaScript. Gestisce quasi tutti i casi:

function clone(src, deep) {

    var toString = Object.prototype.toString;
    if (!src && typeof src != "object") {
        // Any non-object (Boolean, String, Number), null, undefined, NaN
        return src;
    }

    // Honor native/custom clone methods
    if (src.clone && toString.call(src.clone) == "[object Function]") {
        return src.clone(deep);
    }

    // DOM elements
    if (src.nodeType && toString.call(src.cloneNode) == "[object Function]") {
        return src.cloneNode(deep);
    }

    // Date
    if (toString.call(src) == "[object Date]") {
        return new Date(src.getTime());
    }

    // RegExp
    if (toString.call(src) == "[object RegExp]") {
        return new RegExp(src);
    }

    // Function
    if (toString.call(src) == "[object Function]") {

        //Wrap in another method to make sure == is not true;
        //Note: Huge performance issue due to closures, comment this :)
        return (function(){
            src.apply(this, arguments);
        });
    }

    var ret, index;
    //Array
    if (toString.call(src) == "[object Array]") {
        //[].slice(0) would soft clone
        ret = src.slice();
        if (deep) {
            index = ret.length;
            while (index--) {
                ret[index] = clone(ret[index], true);
            }
        }
    }
    //Object
    else {
        ret = src.constructor ? new src.constructor() : {};
        for (var prop in src) {
            ret[prop] = deep
                ? clone(src[prop], true)
                : src[prop];
        }
    }
    return ret;
};

Non sono d'accordo con la risposta con i voti più alti here . Un Clone profondo ricorsivo è molto più veloce dell'approccio JSON.parse (JSON.stringify (obj)) menzionato.

Ed ecco la funzione di riferimento rapido:

function cloneDeep (o) {
  let newO
  let i

  if (typeof o !== 'object') return o

  if (!o) return o

  if (Object.prototype.toString.apply(o) === '[object Array]') {
    newO = []
    for (i = 0; i < o.length; i += 1) {
      newO[i] = cloneDeep(o[i])
    }
    return newO
  }

  newO = {}
  for (i in o) {
    if (o.hasOwnProperty(i)) {
      newO[i] = cloneDeep(o[i])
    }
  }
  return newO
}

Per le persone che desiderano utilizzare la JSON.parse(JSON.stringify(obj))versione, ma senza perdere gli oggetti Date, è possibile utilizzare il secondo argomento del parsemetodo per convertire le stringhe in data:

function clone(obj) {
  var regExp = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
  return JSON.parse(JSON.stringify(x), function(k, v) {
    if (typeof v === 'string' && regExp.test(v))
      return new Date(v);
    return v;
  });
}

Questa non è generalmente la soluzione più efficiente, ma fa ciò di cui ho bisogno. Casi di test semplici sotto ...

function clone(obj, clones) {
    // Makes a deep copy of 'obj'. Handles cyclic structures by
    // tracking cloned obj's in the 'clones' parameter. Functions 
    // are included, but not cloned. Functions members are cloned.
    var new_obj,
        already_cloned,
        t = typeof obj,
        i = 0,
        l,
        pair; 

    clones = clones || [];

    if (obj === null) {
        return obj;
    }

    if (t === "object" || t === "function") {

        // check to see if we've already cloned obj
        for (i = 0, l = clones.length; i < l; i++) {
            pair = clones[i];
            if (pair[0] === obj) {
                already_cloned = pair[1];
                break;
            }
        }

        if (already_cloned) {
            return already_cloned; 
        } else {
            if (t === "object") { // create new object
                new_obj = new obj.constructor();
            } else { // Just use functions as is
                new_obj = obj;
            }

            clones.push([obj, new_obj]); // keep track of objects we've cloned

            for (key in obj) { // clone object members
                if (obj.hasOwnProperty(key)) {
                    new_obj[key] = clone(obj[key], clones);
                }
            }
        }
    }
    return new_obj || obj;
}

Test ciclico dell'array ...

a = []
a.push("b", "c", a)
aa = clone(a)
aa === a //=> false
aa[2] === a //=> false
aa[2] === a[2] //=> false
aa[2] === aa //=> true

Test di funzionalita...

f = new Function
f.a = a
ff = clone(f)
ff === f //=> true
ff.a === a //=> false

Sembra che non ci sia alcun operatore di clone profondo ideale per oggetti di tipo array. Come illustra il codice sottostante, il cloner jQuery di John Resig trasforma le matrici con proprietà non numeriche in oggetti che non sono matrici, e il cloner JSON di RegDwight elimina le proprietà non numeriche. I seguenti test illustrano questi punti su più browser:

function jQueryClone(obj) {
   return jQuery.extend(true, {}, obj)
}

function JSONClone(obj) {
   return JSON.parse(JSON.stringify(obj))
}

var arrayLikeObj = [[1, "a", "b"], [2, "b", "a"]];
arrayLikeObj.names = ["m", "n", "o"];
var JSONCopy = JSONClone(arrayLikeObj);
var jQueryCopy = jQueryClone(arrayLikeObj);

alert("Is arrayLikeObj an array instance?" + (arrayLikeObj instanceof Array) +
      "\nIs the jQueryClone an array instance? " + (jQueryCopy instanceof Array) +
      "\nWhat are the arrayLikeObj names? " + arrayLikeObj.names +
      "\nAnd what are the JSONClone names? " + JSONCopy.names)

// obj target object, vals source object
var setVals = function (obj, vals) {
    if (obj && vals) {
        for (var x in vals) {
            if (vals.hasOwnProperty(x)) {
                if (obj[x] && typeof vals[x] === 'object') {
                    obj[x] = setVals(obj[x], vals[x]);
                } else {
                    obj[x] = vals[x];
                }
            }
        }
    }
    return obj;
};

function clone(obj)
 { var clone = {};
   clone.prototype = obj.prototype;
   for (property in obj) clone[property] = obj[property];
   return clone;
 }




clone