Soru JavaScript'te bir nesneyi derinlemesine klonlamanın en etkili yolu nedir?


Bir JavaScript nesnesini kopyalamanın en etkili yolu nedir? gördüm obj = eval(uneval(o)); kullanılıyor, ama Bu standart olmayan ve sadece Firefox tarafından desteklenen.

 Ben gibi şeyler yaptım obj = JSON.parse(JSON.stringify(o)); ama verimliliği sorgulayın.

 Ayrıca çeşitli kusurları olan yinelenen kopyalama işlevlerini gördüm.
Kanonik çözüm bulunmadığı için şaşırdım.


4548
2018-06-06 14:59


Menşei


Eval kötülük değildir. Eval'ı kullanmak zayıftır. Yan etkilerinden korkuyorsanız yanlış kullanıyorsunuzdur. Korktuğunuz yan etkiler, kullanmanın nedenleri. Bu arada hiç kimse sorunuzu cevapladı mı? - Prospero
Nesneleri klonlamak, özellikle rastgele koleksiyonların özel objeleriyle zor bir iştir. Muhtemelen bu yüzden bunu yapmak için kutudan çıkma yolu yoktur. - b01
eval() genellikle kötü bir fikir çünkü Birçok Javascript motorunun optimistleri, üzerinden ayarlanan değişkenlerle uğraşırken kapanmak zorunda eval. Sadece sahip olmak eval() Kodunuzda daha kötü performansa yol açabilir. - user568458
Olası kopya Bir JavaScript nesnesini kopyalamanın en zarif yolu - John Slegers
İşte en yaygın klonlama nesneleri türleri arasında bir performans karşılaştırması: jsben.ch/#/t917Z - EscapeNetscape


Cevaplar:


Not: Bu, başka bir cevaba cevaptır, bu soruya doğru bir cevap değildir. Hızlı nesne klonlaması yapmak istiyorsanız lütfen Corban'ın cevabındaki tavsiyesi bu soruya


Ben şunu belirtmek isterim .clone() yöntem jQuery sadece DOM öğelerini klonlar. JavaScript nesnelerini kopyalamak için şunları yaparsınız:

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

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

Daha fazla bilgi bulunabilir jQuery belgeleri.

Ayrıca, derin kopyanın aslında yukarıda gösterilenlerden çok daha akıllı olduğunu da belirtmek isterim - birçok tuzaktan (örneğin bir DOM öğesini derinlemesine genişletmeye çalışmaktan) sakınmak mümkün. JQuery çekirdeğinde ve eklentilerinde büyük etki için sıklıkla kullanılır.


4067



Farkına varmamış olanlar için, John Resig'in cevabı muhtemelen bir çeşit cevap / açıklama olarak tasarlandı. ConroyP'nin cevabısoruna doğrudan cevap yerine. - S. Kirby
@ThiefMaster github.com/jquery/jquery/blob/master/src/core.js 276 satırında (başka bir şeyi yapan bir kod var ama "JS'de bunu nasıl yapacağınız" için kod var :) - Rune FS
İlgilendiğiniz herkes için jQuery derin kopyasının arkasındaki JS kodu: github.com/jquery/jquery/blob/master/src/core.js#L265-327 - Alex W
Woah! Sadece süper-açık olmak gerekirse: Bu cevabın neden doğru cevap olarak seçildiğine dair hiçbir fikriniz yok, bu aşağıda verilen cevapların cevabıydı: stackoverflow.com/a/122190/6524 (bu tavsiye edildi .clone(), bu bağlamda kullanmak için doğru kod değildir. Ne yazık ki, bu soru birçok revizyondan geçti, orijinal tartışma artık belli değil! Lütfen hızınızı önemsiyorsanız, Corban'ın tavsiyelerini takip edin ve bir döngü yazın veya özellikleri doğrudan yeni bir nesneye kopyalayın. Veya kendiniz için test edin! - John Resig
JQuery kullanmadan bunu nasıl yaparsınız? - Awesomeness01


Bu karşılaştırma ölçütü: http://jsben.ch/#/bWfk9

Hızın temel bir endişe olduğu önceki testlerimde buldum

JSON.parse(JSON.stringify(obj))

bir nesneyi derin klonlamak için en hızlı yol olmak jQuery.extend derin bayrağı ile% 10-20 doğru).

derin bayrak yanlış (sığ klon) olarak ayarlandığında jQuery.extend oldukça hızlıdır. Bu, iyi bir seçenektir, çünkü tür doğrulama için ekstra bir mantık içerir ve tanımlanmamış özellikler vb. Üzerine kopyalama yapmaz, ancak bu sizi biraz da yavaşlatacaktır.

Klonlamaya çalıştığınız nesnelerin yapısını biliyorsanız veya iç içe geçmiş dizilerden kaçınılabiliyorsanız basit bir yazı yazabilirsiniz. for (var i in obj) hasOwnProperty kontrol ederken nesneyi klonlamak için döngü ve jQuery'den çok daha hızlı olacaktır.

Son olarak, bilinen bir nesne yapısını bir sıcak döngüde klonlamaya çalışıyorsanız, sadece klon prosedürünü kaplayarak ve nesneyi manuel olarak oluşturarak ÇOK DAHA FAZLA PERFORMANS ALABİLİRSİNİZ.

JavaScript izleme motorları optimizasyon emiyor for..in döngüler ve hasOwnProperty kontrol etmek de sizi yavaşlatır. Hız mutlak olduğunda manüel klonlama gerekir.

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

Kullanarak dikkatli olun JSON.parse(JSON.stringify(obj)) üzerinde yöntem Date nesneler - JSON.stringify(new Date()) ISO formatındaki tarihin dize gösterimini döndürür. JSON.parse()  değil geri dönüştür Date nesne. Daha fazla bilgi için bu cevabı gör.

Ayrıca, en azından Chrome 65'de yerel klonlamanın gitmenin yolu olmadığını lütfen unutmayın. Göre bu JSPerf, yeni bir işlev oluşturarak yerel klonlama yapmak neredeyse 800x Kurul boyunca inanılmaz derecede hızlı olan JSON.stringify'ı kullanmaktan daha yavaş.


1877



@trysis Object.create nesneyi klonlama değil, prototip nesnesini kullanıyor ... jsfiddle.net/rahpuser/yufzc1jt/2 - rahpuser
Bu yöntem aynı zamanda keys senden object, var functions değerleri olarak, çünkü JSON işlevleri desteklemiyor. - Karlen Kishmiryan
Bunu da unutmayın JSON.parse(JSON.stringify(obj)) Tarih Nesneleri de tarihi tekrar UTC dize gösterimde ISO8601 biçim. - dnlgmzddr
JSON yaklaşımı ayrıca dairesel referanslar üzerinde boğuluyor. - rich remer
@velop, Object.assign ({}, objToClone) bir sığ klonu gibi görünüyor - dev araçlar konsolunda oynatırken bunu kullanarak, nesne klonu hala klonlanmış nesnenin bir referansını işaret etti. Bu yüzden burada gerçekten geçerli olduğunu sanmıyorum. - Garrett Simpson


Yalnızca değişkenleriniz olduğunu ve nesnenizdeki herhangi bir işlevi olmadığını varsayalım:

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

402



Bu yaklaşımın daha önce bulduğum gibi, eğer nesnenizin herhangi bir işlevi varsa (benimki iç alıcıları ve belirleyicileri var) o zaman bunlar dizginlendiğinde kaybolurlar. Eğer ihtiyacınız olan tek şey bu kadar iyi .. - Markive
@Jason, Bu yöntemin, sığ kopyalamadan (derin bir nesne üzerinde) daha yavaş olmasının nedeni, bu yöntemin, tanım gereği, derin kopyalar olmasıdır. Ama o zamandan beri JSON yerel kodda (çoğu tarayıcıda) uygulanır, bu diğer javascript tabanlı derin kopyalama çözümlerini kullanmaktan çok daha hızlı olacaktır ve ara sıra javascript tabanlı sığ kopyalama tekniğinden daha hızlı olun (bakınız: jsperf.com/cloning-an-object/79). - MiJyn
JSON.stringify({key: undefined}) //=> "{}" - Web_Designer
bu teknik de hepsini yok edecek Date nesnenin içinde saklanan nesneleri, bunları dize biçimine dönüştürür. - fstab
JSON özelliklerinin bir parçası olmayan herhangi bir şeyi kopyalayamaz (json.org) - cdmckay


Yapısal Klonlama

HTML5 tanımlar dahili bir "yapılandırılmış" klonlama algoritması Bu nesnelerin derin klonları oluşturabilir. Bazı yerleşik tiplerle hala sınırlıdır, ancak JSON tarafından desteklenen birkaç türe ek olarak, Tarihler, RegExps, Haritalar, Kümeler, Bloblar, FileLists, ImageDatas, seyrek Diziler, Typed Arraysve muhtemelen gelecekte daha fazla. Ayrıca, klonlanmış verilerdeki referansları koruyarak, JSON için hatalara neden olabilecek döngüsel ve özyineleli yapıları desteklemesini sağlar.

Tarayıcılar Doğrudan Destek: Yakında geliyor?

Tarayıcılar şu anda yapılandırılmış klonlama algoritması için doğrudan bir arayüz sağlamaz, ancak bir global structuredClone() işlev aktif olarak tartışılıyor GitHub üzerinde whatwg / html # 793 ve yakında geliyor olabilir! Şu anda önerildiği gibi, çoğu amaç için kullanmak şu kadar basit olacaktır:

const clone = structuredClone(original);

Bu gönderilinceye kadar, tarayıcıların yapılandırılmış klon uygulamaları sadece dolaylı olarak gösterilir.

Eşzamansız Geçici Çözüm: Kullanılabilir.

Varolan API'larla yapılandırılmış bir klon oluşturmanın alttan yükleme yolu, verileri bir bağlantı noktasından aktarmaktır. MessageChannels. Diğer bağlantı noktası bir message ekli yapılandırılmış bir klon ile olay .data. Ne yazık ki, bu olayları dinlemek zorunlu olarak asenkrondir ve senkronize alternatifler daha az pratiktir.

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);

Örnek kullanım:

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();

Eşzamanlı Çözümler: Korkunç!

Yapılandırılmış klonları eşzamanlı olarak oluşturmak için iyi bir seçenek yoktur. İşte bunun yerine birkaç pratik hack var.

history.pushState() ve history.replaceState() her ikisi de ilk bağımsız değişkeninin yapılandırılmış bir kopyasını oluşturur ve bu değeri history.state. Bunu, böyle bir nesnenin yapılandırılmış bir klonunu oluşturmak için kullanabilirsiniz:

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

Örnek kullanım:

'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();

Senkronize olsa da, bu çok yavaş olabilir. Tarayıcı geçmişini işlemek ile ilişkili tüm yükü üstlenir. Bu yöntemi tekrar tekrar aramak, Chrome'un geçici olarak yanıt vermemesine neden olabilir.

Notification inşaatçı ilişkili verilerin yapılandırılmış bir klonunu oluşturur. Ayrıca kullanıcıya bir tarayıcı bildirimi görüntülemeye çalışır, ancak bildirim izni istemediğiniz sürece bu işlem sessizce başarısız olur. Başka amaçlar için izniniz varsa, oluşturduğumuz bildirimi hemen kapatırız.

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

Örnek kullanım:

'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();


274



@rynah Sadece tekrar spec ile baktı ve haklısın: history.pushState() ve history.replaceState() yöntemleri senkronize olarak ayarlandı history.state İlk argümanlarının yapılandırılmış bir klonuna. Biraz garip ama işe yarıyor. Cevabımı şimdi güncelliyorum. - Jeremy
Bu çok yanlış! Bu API bu şekilde kullanılmamalıdır. - Fardin
Firefox’ta pushState’i uygulayan adam olarak, bu hack’de tuhaf bir gurur ve tiksinti hissediyorum. Aferin çocuklar. - Justin L.


Yerleşik biri olmasaydı, deneyebilirsiniz:

    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;
    }


273



JQuery çözümü DOM öğeleri için çalışacak, sadece herhangi bir Nesne değil. Mootooller aynı sınıra sahiptir. Keşke herhangi bir nesne için genel bir "klon" olsaydı ... Özyineli çözüm her şey için çalışmalı. Muhtemelen gitmenin yolu. - jschrab
Klonlanan nesne parametreler gerektiren bir kurucuya sahipse, bu işlev kırılır. Sanki "var temp = new Object ()" e değiştirebiliriz ve her durumda çalışır mı? - Andrew Arnott
Andrew, eğer var temp = new Object () öğesine değiştirirseniz, klonunuz orijinal nesne ile aynı prototipe sahip olmaz. Kullanmayı deneyin: 'var newProto = function () {}; newProto.prototype = obj.constructor; var temp = yeni newProto (); ' - limscoder
Limscoder'ın cevabına benzer şekilde, kurucuyu aramadan nasıl yapılacağına ilişkin cevabımı aşağıya bakın: stackoverflow.com/a/13333781/560114 - Matt Browne
Alt bölümlere (yani nesnelerin ağlarına) referanslar içeren nesneler için, bu işe yaramaz: İki başvuru aynı alt nesneye işaret ediyorsa, kopyanın iki farklı kopyası vardır. Yinelemeli referanslar varsa, işlev hiçbir zaman sonlanmayacaktır (iyi, en azından istediğiniz gibi değil :-) Bu genel durumlar için, önceden kopyalanmış nesnelerin bir sözlüğünü eklemeniz ve daha önce kopyalayıp kopyalamamış olmanız gerektiğini kontrol etmeniz gerekir. ... Basit bir dil kullandığınızda programlama karmaşıktır - virtualnobi


Bir satırdaki bir nesneyi klonlama (derin klonlama) için etkili yol

bir Object.assign yöntem ECMAScript 2015 (ES6) standardının bir parçasıdır ve tam olarak ihtiyacınız olanı yapar.

var clone = Object.assign({}, obj);

Object.assign () yöntemi, tüm sayılabilir tüm özelliklerin değerlerini bir veya daha fazla kaynak nesneden bir hedef nesneye kopyalamak için kullanılır.

Daha fazla oku...

polyfill eski tarayıcıları desteklemek için:

if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        nextSource = Object(nextSource);

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}

132



Bu yinelemeli olarak kopyalanmaz, bu nedenle bir nesneyi klonlama sorununa gerçekten bir çözüm sunmaz. - mwhite
Bu yöntem işe yaradı, ancak birkaç tane test ettim ve _.extend ({}, (obj)) en hızlı BY FAR'dı: JSON.parse'dan 20x daha hızlı ve Object.assign'dan% 60 daha hızlı. Tüm alt nesneleri oldukça iyi kopyalar. - Nico
@mwhite klon ve derin klon arasında bir fark var. Bu cevap aslında klonlanır, ancak derin klonlanmaz. - Meirion Hughes
op derin klon istedi. Bu derin klon yapmaz. - user566245
op'un sorusunu okumadan çok fazla Object.assign yanıtı var. - martin8768


Kod:

// extends 'from' object with members from 'to'. If 'to' is null, a deep clone of 'from' is returned
function extend(from, to)
{
    if (from == null || typeof from != "object") return from;
    if (from.constructor != Object && from.constructor != Array) return from;
    if (from.constructor == Date || from.constructor == RegExp || from.constructor == Function ||
        from.constructor == String || from.constructor == Number || from.constructor == Boolean)
        return new from.constructor(from);

    to = to || new from.constructor();

    for (var name in from)
    {
        to[name] = typeof to[name] == "undefined" ? extend(from[name], null) : to[name];
    }

    return to;
}

Ölçek:

var obj =
{
    date: new Date(),
    func: function(q) { return 1 + q; },
    num: 123,
    text: "asdasd",
    array: [1, "asd"],
    regex: new RegExp(/aaa/i),
    subobj:
    {
        num: 234,
        text: "asdsaD"
    }
}

var clone = extend(obj);

91



ne dersin var obj = {} ve obj.a = obj - neaumusic
Bu işlevi anlamıyorum. varsaymak from.constructor olduğu Date Örneğin. Üçüncü nasıl olur if test 2'ye geldiğinde if sınama başarılı olur ve işlev geri dönmesine neden olur Date != Object && Date != Array)? - Adam McKee
@AdamMcKee Çünkü javascript argümanı geçen ve değişken ataması zor. Bu yaklaşım, tarihler de dahil olmak üzere harika çalışır (ki bu gerçekten ikinci test tarafından ele alınır). jsfiddle.net/zqv9q9c6. - brichins
* "Değişken atama" değil "parametre atama" (bir işlev gövdesi içinde) kastediyorum. Her ikisini de anlamaya yardımcı olsa da. - brichins
@NickSweeting: Deneyin - çalışıyor olabilir. Değilse - düzeltin ve cevabı güncelleyin. Burada toplulukta böyle çalışıyor :) - Kamarey


Kullandığım şey bu:

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

81



Bu doğru görünmüyor. cloneObject({ name: null }) => {"name":{}} - Niyaz
Bu javascript'te başka bir aptal şeyden kaynaklanıyor typeof null > "object" fakat Object.keys(null) > TypeError: Requested keys of a value that is not an object. koşulu değiştirmek if(typeof(obj[i])=="object" && obj[i]!=null) - Vitim.us
Bu devralınan sayısız özellikleri atayacak obj doğrudan klonla, ve varsayalım obj sade bir nesne. - RobG
Bu, sayısal tuşlara sahip nesnelere dönüştürülen dizileri de dağıtır. - blade
Eğer boş kullanmazsanız sorun değil. - Jorge Bucaran


Performansa göre derin kopya: En iyi ihtimalle en kötü

  • Yeniden Atama "=" (dizi dizileri, dizi dizileri)
  • Dilim (dizi dizileri, dizi dizileri - sadece)
  • Birleştirme (dize dizileri, sayı dizileri - yalnızca)
  • Özel işlev: for-loop veya yinelemeli kopya
  • jQuery'nin $ .extend
  • JSON.parse (dizi dizileri, sayı dizileri, nesne dizileri - sadece)
  • Underscore.js's _.clone (dizi dizileri, dizi dizileri)
  • Lo-Dash'ın _.cloneDeep'i

Derin bir dizi dizeleri veya sayıları kopyalayın (bir seviye - referans işaretçisi yok):

Bir dizi sayı ve dizge içerdiğinde - .slice (), .concat (), .splice () gibi işlevler, "=" atama operatörü ve Underscore.js'in klon fonksiyonu; dizinin öğelerinin derin bir kopyasını yapacak.

Yeniden atama en hızlı performansa sahip olduğunda:

var arr1 = ['a', 'b', 'c'];
var arr2 = arr1;
arr1 = ['a', 'b', 'c'];

Ve .slice (), .concat () 'dan daha iyi bir performansa sahiptir. http://jsperf.com/duplicate-array-slice-vs-concat/3

var arr1 = ['a', 'b', 'c'];  // Becomes arr1 = ['a', 'b', 'c']
var arr2a = arr1.slice(0);   // Becomes arr2a = ['a', 'b', 'c'] - deep copy
var arr2b = arr1.concat();   // Becomes arr2b = ['a', 'b', 'c'] - deep copy

Derin nesneleri bir dizi kopyalayın (iki veya daha fazla seviye - referans işaretçileri):

var arr1 = [{object:'a'}, {object:'b'}];

Özel bir işlev yazın ($ .extend () veya JSON.parse'dan daha hızlı bir performansa sahip):

function copy(o) {
   var out, v, key;
   out = Array.isArray(o) ? [] : {};
   for (key in o) {
       v = o[key];
       out[key] = (typeof v === "object" && v !== null) ? copy(v) : v;
   }
   return out;
}

copy(arr1);

Üçüncü taraf hizmet programı işlevlerini kullanın:

$.extend(true, [], arr1); // Jquery Extend
JSON.parse(arr1);
_.cloneDeep(arr1); // Lo-dash

JQuery'nin $ .extend'inin daha iyi bir performansa sahip olduğu yerler:


64



Bir kaçını test ettim ve _.extend ({}, (obj)) en hızlı BY FAR'dı: JSON.parse'dan 20x daha hızlı ve Object.assign'dan% 60 daha hızlı. Tüm alt nesneleri oldukça iyi kopyalar. - Nico
@NicoDurand - Performans testleriniz çevrimiçi mi? - tfmontague
Bütün örneklerin sığ, tek seviye. Bu iyi bir cevap değil. Soru ilgili derin klonlama, en az iki seviye. - Karl Morrison
Derin bir nesne, bir nesnenin, diğer nesneler için referans göstergelerini kullanmadan, bütünüyle kopyalanmasıdır. JQuery.extend () ve özel işlev (yinelemeli) gibi nesneleri "Nesnelerin bir dizisini kopyala" bölümü altındaki teknikler "en az iki düzey" ile nesneleri kopyalar. Yani, tüm örnekler "tek seviye" kopya değildir. - tfmontague
Özel kopyalama işlevinizi seviyorum, ancak boş değerleri hariç tutmalısınız, aksi halde tüm boş değerler nesnelere dönüştürülür, örn .: out[key] = (typeof v === "object" && v !== null) ? copy(v) : v; - josi


var clone = function() {
    var newObj = (this instanceof Array) ? [] : {};
    for (var i in this) {
        if (this[i] && typeof this[i] == "object") {
            newObj[i] = this[i].clone();
        }
        else
        {
            newObj[i] = this[i];
        }
    }
    return newObj;
}; 

Object.defineProperty( Object.prototype, "clone", {value: clone, enumerable: false});

56