Soru Bir JavaScript nesnesini doğru şekilde nasıl kopyalarım?


Bir neslim var x. Onu nesne olarak kopyalamak istiyorum y, böyle değişiklikler y değiştirmeyin x. Yerleşik JavaScript nesnelerinden türetilen nesnelerin kopyalanmasının fazladan, istenmeyen özelliklere neden olacağını fark ettim. Bu bir problem değil, çünkü kendi yapılı, yapılı nesnelerden birini kopyalıyorum.

Bir JavaScript nesnesini doğru şekilde nasıl kopyalarım?


2403


Menşei


Bu soruya bakın: stackoverflow.com/questions/122102/... - Niyaz
JSON için kullanıyorum mObj=JSON.parse(JSON.stringify(jsonObject)); - Lord Loh.
Kimsenin neden önermediğini anlamıyorum Object.create(o)yazarın istediği her şeyi yapar mı? - froginvasion
var x = { deep: { key: 1 } }; var y = Object.create(x); x.deep.key = 2;  Bunu yaptıktan sonra, y.deep.key Ayrıca 2 olacak, böylece Object.create klonlama için KULLANILAMAZ ... - Ruben Stolk
@ r3wt çalışmayacak ... Lütfen çözümün temel testini yaptıktan sonra gönderin .. - akshay


Cevaplar:


Güncellenmiş cevap

Sadece kullan Object.assign () önerildiği gibi İşte

Ancak bunun sadece sığ bir kopya oluşturduğuna dikkat edin. İç içe geçmiş nesneler hala referans olarak kopyalanır.


Eski cevap

JavaScript’deki herhangi bir nesne için bunu yapmak basit ya da basit olmayacaktır. Nesnenin prototipinde bırakılan ve yeni örneğe kopyalanmaması gereken prototipinden hatalı olarak alma problemi ile karşılaşacaksınız. Örneğin, bir clone yöntem Object.prototypeBazı cevaplarda gösterildiği gibi, bu özelliği açıkça atlamanız gerekecek. Ama ya başka ek yöntemler var ise Object.prototypeya da bilmediğiniz diğer ara prototipler? Bu durumda, yapmamanız gereken özellikleri kopyalayacaksınız. Bu nedenle, öngörülemeyen, yerel olmayan özellikleri hasOwnProperty yöntem.

Sayısız niteliklere ek olarak, gizli özelliklere sahip nesneleri kopyalamaya çalıştığınızda daha zorlu bir sorunla karşılaşırsınız. Örneğin, prototype bir işlevin gizli bir özelliğidir. Ayrıca, bir nesnenin prototipine öznitelikle başvurulur. __proto__Ayrıca, gizlenen ve kaynak nesnenin öznitelikleri üzerinde yinelenen bir for / in loop tarafından kopyalanmayacaktır. bence __proto__ Firefox'un JavaScript yorumlayıcısına özel olabilir ve diğer tarayıcılarda farklı olabilir, ancak resmi alırsınız. Her şey sayılabilir değil. Adını biliyorsanız, gizli bir özniteliği kopyalayabilirsiniz, ancak otomatik olarak keşfetmenin herhangi bir yolunu bilmiyorum.

Zarif bir çözüm arayışındaki bir başka sapma, prototip mirasın doğru şekilde ayarlanması sorunudur. Kaynak nesnenizin prototipi ise Objectsonra basitçe yeni bir genel nesne ile {} işe yarayacak, ama eğer kaynağın prototipi bir soyundan geliyorsa ObjectDaha sonra, kullanarak atladığınız prototipin ek üyelerini kaçırmaya başlayacaksınız. hasOwnProperty filtre, ya da prototip vardı, ancak ilk sırada sayılabilir değildi. Bir çözüm, kaynak nesnenin çağrılması olabilir. constructor İlk kopya nesnesini almak ve daha sonra niteliklerini kopyalamak için özellik, ancak daha sonra hala numaralandırılamayan öznitelikleri almayacaksınız. Örneğin, Date nesne verilerini gizli bir üye olarak saklar:

function clone(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    var copy = obj.constructor();
    for (var attr in obj) {
        if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
    }
    return copy;
}

var d1 = new Date();

/* Executes function after 5 seconds. */
setTimeout(function(){
    var d2 = clone(d1);
    alert("d1 = " + d1.toString() + "\nd2 = " + d2.toString());
}, 5000);

İçin tarih dizesi d1 arkasında 5 saniye olacak d2. Birini yapmanın bir yolu Date Bir diğeriyle aynı şeyi aramak setTime yöntem, ancak bu belirli Date sınıf. Bu soruna kurşun geçirmez bir genel çözüm olduğunu düşünmüyorum, yine de yanlış olmasından memnun olurum!

Genel derin kopyalamayı uygulamak zorunda kaldığımda, sadece bir düzlem kopyalamak zorunda kalacağımı düşünerek uzlaşmayı başardım. Object, Array, Date, String, Numberveya Boolean. Son 3 tip değişmezdir, bu yüzden sığ bir kopya yapabilirim ve bu konuda endişelenmeyin. Ayrıca içerdiği herhangi bir öğeyi Object veya Array Aynı zamanda bu listedeki 6 basit türden biri olacaktır. Bu, aşağıdaki gibi bir kodla gerçekleştirilebilir:

function clone(obj) {
    var copy;

    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

Yukarıdaki işlev, nesneler ve dizilerdeki veriler bir ağaç yapısı oluşturduğu sürece, bahsettiğim 6 basit tip için yeterli şekilde çalışacaktır. Yani, nesnede aynı verilere birden fazla başvuru yoktur. Örneğin:

// This would be cloneable:
var tree = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "right" : null,
    "data"  : 8
};

// This would kind-of work, but you would get 2 copies of the 
// inner node instead of 2 references to the same copy
var directedAcylicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};
directedAcyclicGraph["right"] = directedAcyclicGraph["left"];

// Cloning this would cause a stack overflow due to infinite recursion:
var cyclicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};
cyclicGraph["right"] = cyclicGraph;

Herhangi bir JavaScript nesnesini işleyemez, ancak attığınız herhangi bir şey için çalışacağını varsaymazsanız birçok amaç için yeterli olabilir.


1313



neredeyse bir nodejs'de gayet iyi çalıştı - sadece (var i = 0, var len = obj.length; i <len; ++ i) {- için satırını değiştirmek zorunda kaldı (var i = 0; i <obj.length; + + i) { - Trindaz
Gelecekteki googlers için: aynı derin kopya, 'return' ifadelerini kullanmak yerine referansları tekrarlı olarak iletmek gist.github.com/2234277 - Trindaz
Günümüzde JSON.parse(JSON.stringify([some object]),[some revirer function]) çözüm olmak mı? - KooiInc
İlk snippet'te olmaması gerektiğine emin misin? var cpy = new obj.constructor()? - cyon
Nesne ataması, Chrome'da gerçek bir kopyasını oluşturmuyor, orijinal nesneyi referans gösteriyor - JSON.stringify ve JSON.parse kullanılarak sona erdi. - 1owk3y


JQuery ile şunları yapabilirsiniz: sığ kopya ile uzatmak:

var copiedObject = jQuery.extend({}, originalObject)

copiedObject öğesinde sonraki değişiklikler originalObject öğesini etkilemez ve bunun tersi de geçerlidir.

Ya da derin kopya:

var copiedObject = jQuery.extend(true, {}, originalObject)

713



ya da: var copiedObject = jQuery.extend({},originalObject); - Grant McLean
Derin kopya için ilk param olarak doğru belirtmek için de yararlıdır: jQuery.extend(true, {}, originalObject); - Will Shaver
Evet, bu bağlantıyı faydalı buldum (Pascal ile aynı çözüm) stackoverflow.com/questions/122102/... - Garry English
@Will Tıraş Makinesi - EVET! Bu kadar! Derin kopya seçeneği olmadan benim için çalışmadı! - thorinkor
Sadece bir not, bu kopyalamaz proto orijinal nesnenin kurucusu - Sam Jones


Nesnenizdeki işlevleri kullanmazsanız, çok basit bir astar aşağıdaki olabilir:

var cloneOfA = JSON.parse(JSON.stringify(a));

Bu, nesneleri, dizileri, dizeleri, boole ve sayıları içeren her türlü nesne için çalışır.

Ayrıca bakınız tarayıcıların yapılandırılmış klon algoritması hakkında bu makale Bir işçiye mesaj gönderirken kullanılır. Ayrıca derin klonlama için bir işlev içerir.


692



Bunun yalnızca test için kullanılabileceğini unutmayın. Birincisi, zaman ve hafıza tüketimi açısından optimal olmaktan çok uzaktır. İkincisi, tüm tarayıcılar bu yöntemlere sahip değildir. - Nux
@Nux, Neden zaman ve bellek açısından optimal değil? MiJyn şöyle diyor: "Bu yöntemin sığ kopyalamaya (derin bir nesnede) göre daha yavaş olmasının nedeni, bu yöntemin, tanım olarak, derin kopyalar olmasıdır. Ancak JSON, yerel kodda (çoğu tarayıcıda) uygulandığından, bu daha hızlı olacaktır. Diğer javascript tabanlı derin kopyalama çözümlerini kullanmaktan ve bazen javascript tabanlı bir sığ kopyalama tekniğinden daha hızlı olabilir (bakınız: jsperf.com/cloning-an-object/79). stackoverflow.com/questions/122102/... - BeauCielBleu
Ekim 2014 için buna bir güncelleme eklemek istiyorum. Chrome 37+, JSON.parse (JSON.stringify (oldObject)) ile daha hızlıdır; Bunu kullanmanın yararı, bir javascript motorunun istediği zaman daha iyi bir şey görmesini ve optimize etmesini çok kolay olmasıdır. - mirhagk
Nesnenin tekdüzenlenebilen şeyler gibi olması durumunda JSON'un her tarafına zarar verebilir Sonsuzluk, Tanımsızvb. Bu nesneyi deneyin: a = { b: Infinity, c: undefined } - kumar_harsh
2016 güncellemesi: Bu, hemen hemen her tarayıcıda yaygın olarak kullanılmalıdır. (görmek Kullanabilirmiyim...) Şimdi asıl soru yeterince verimli olup olmadığıdır. - James Foster


ECMAScript 6'da var Object.assign Tüm sayılabilir öz özelliklerin değerlerini bir nesneden diğerine kopyalar. Örneğin:

var x = {myProp: "value"};
var y = Object.assign({}, x); 

Ancak iç içe geçmiş nesnelerin hala referans olarak kopyalandığını unutmayın.


509



Evet, buna inanıyorum Object.assign gitmenin yolu. Bunu çok kolay doldurmak da kolaydır: gist.github.com/rafaelrinaldi/43813e707970bd2d77fa - Rafael
Ancak bunun sadece sığ bir kopya oluşturduğuna dikkat edin. İç içe geçmiş nesneler hala referans olarak kopyalandı! - ohager
Ayrıca, bunun nesne edebi araçlarıyla tanımlanan "yöntemler" üzerinden kopyalanacağını unutmayın (bunlar Hangi sayılabilir) ama değil "sınıf" mekanizmasıyla ifade edilen yöntemler (bunlar değilnumaralandırılabilir). - Marcus Junius Brutus
Bunun, Edge hariç IE tarafından desteklenmediğini belirtmeliyim. Bazı insanlar bunu hala kullanıyor. - Saulius
Bu, cevabını @EugeneTiurin ile aynıdır. - Wilt


Birçok cevap var, ama bunlardan hiç biri yok Object.create ECMAScript 5'ten, tam olarak size bir kopyasını vermez, ancak kaynağı yeni nesnenin prototipi olarak ayarlar.

Dolayısıyla, bu soruya kesin bir cevap değildir, ancak tek satırlık bir çözümdür ve bu nedenle de zariftir. Ve en iyi 2 durum için çalışır:

  1. Böyle bir kalıtımın yararlı olduğu yer (duh!)
  2. Kaynak nesnenin değiştirilmeyeceği yerde, 2 nesne arasındaki ilişkiyi sorun oluşturmaz.

Örnek:

var foo = { a : 1 };
var bar = Object.create(foo);
foo.a; // 1
bar.a; // 1
foo.a = 2;
bar.a; // 2 - prototype changed
bar.a = 3;
foo.a; // Still 2, since setting bar.a makes it an "own" property

Neden bu çözümü üstün görüyoruz? Yerli, dolayısıyla döngü yok, özyineleme yok. Ancak, eski tarayıcıların bir polifiliğe ihtiyacı olacaktır.


114



Not: Object.create, derin bir kopya değildir (itpastorn, herhangi bir özyineleme belirtmemiştir). Kanıt: var a = {b:'hello',c:{d:'world'}}, b = Object.create(a); a == b /* false */; a.c == b.c /* true */; - zamnuts
Bu prototip kalıtım, klonlama değil. Bunlar tamamen farklı şeyler. Yeni nesnenin kendi özellikleri yoktur, sadece prototipin özelliklerine işaret eder. Klonlama noktası, başka bir nesnede herhangi bir özelliğe gönderme yapmayan yeni ve yeni bir nesne oluşturmaktır. - d13
Sana tamamen katılıyorum. Aynı şekilde, 'amaçlanmış' olabileceği gibi klonlama olmadığını da kabul ediyorum. Ancak, insanlara gel, standartlaştırılmamış belirsiz çözümler bulmaya çalışmak yerine JavaScript'in doğasını kucakla. Elbette, prototipleri sevmiyorsun ve hepsi senin için "falan", ama ne yaptığını biliyorsan aslında çok faydalılar. - froginvasion
@RobG: Bu makalede, başvuru ve klonlama arasındaki fark açıklanmaktadır: en.wikipedia.org/wiki/Cloning_(programming). Object.create ebeveynlerin özelliklerine referanslar yoluyla işaret eder. Bu, ebeveynin mülk değerleri değiştiğinde, çocuğun da değişeceği anlamına gelir. Bu, iç içe geçmiş diziler ve kodunuzda bulunamayan hatalara yol açabilecek nesneler ile bazı şaşırtıcı yan etkilere sahiptir; jsbin.com/EKivInO/2. Klonlanmış bir nesne, üst öğe ile aynı özelliklere ve değerlere sahip, ancak üst öğeye bağlı olmayan, tamamen yeni ve bağımsız bir nesnedir. - d13
Bu, insanları yanlış yönlendirir ... Object.create (), kalıtım için bir araç olarak kullanılabilir, ancak klonlama ona yakın bir yer değildir. - prajnavantha


Bir kod satırında bir Javascript nesnesini kopyalamanın zarif bir yolu

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

105



Aptal soru için özür dilerim ama neden Object.assign iki parametreyi almak value polyfill işlevinde sadece bir parametre alır? - Qwertie
@Qwertie dün Tüm argümanlar yinelenir ve son geçiş argümanından özelliklerin önceliklendirilmesiyle tek bir nesneye birleştirilir. - Eugene Tiurin
Oh, anladım, teşekkürler arguments önce nesne.) Bulmakta zorluk çekiyorum Object() Google üzerinden ... bu bir tahmin değil mi? - Qwertie
Bu sadece sığ bir "klonlama" yapacak - Marcus Junius Brutus


Başına MDN:

  • Sığ kopya istiyorsanız, kullanın Object.assign({}, a)
  • "Derin" kopya için kullan JSON.parse(JSON.stringify(a))

Dış kütüphanelere ihtiyaç yoktur, ancak kontrol etmeniz gerekir. önce tarayıcı uyumluluğu.


105



JSON.parse (JSON.stringify (a)) güzel görünüyor, ancak kullanmadan önce, istediğiniz koleksiyon için gereken süreyi karşılaştırmanızı tavsiye ederim. Nesne boyutuna bağlı olarak, bu en hızlı seçenek olmayabilir. - Edza
Fark ettiğim JSON yöntemi, tarih nesnelerini dizelere dönüştürür, ancak tarihlere geri dönmez. Javascript'teki zaman dilimlerinin eğlencesiyle uğraşmalı ve herhangi bir tarihte manuel olarak düzeltmelisiniz. Tarihler dışında başka türler için benzer durumlar olabilir - Steve Seeger
Date için anı clone işlevsellik. daha fazlasını gör momentjs.com/docs/#/parsing/moment-clone - Tareq


Eğer sığ bir kopya ile tamam değilseniz, underscore.js kütüphanesinde bir klon yöntem.

y = _.clone(x);

ya da onu uzatabilirsin

copiedObject = _.extend({},originalObject);

70



Ve lodash bir cloneDeep - dule
Teşekkürler. Bu tekniği bir Meteor sunucusunda kullanma. - Turbo
Merci adam! Bu benim için bir iş yaptı lodash'ın şaşırtıcı bir süredir kullanıyorum. Bildiğim kadarıyla bir vue projesinde sıkışmış var vue, açısal gibi bir nesneyi klonlamak için yerleşik bir fonksiyona sahip değildir (angular.copy) - Arnaud Bouchot


İnternette çoğu çözümle ilgili birçok sorun var. Bu yüzden, kabul edilen cevabın neden kabul edilmemesi gerektiğini de içeren bir takip yapmaya karar verdim.

başlangıç ​​durumu

istiyorum Derin kopya bir Javascript Object tüm çocukları ve çocukları ile vb. Ama normal bir geliştirici olmadığımdan, benim Object vardır normal  properties, circular structures ve hatta nested objects.

Hadi bir circular structure ve bir nested object ilk.

function Circ() {
    this.me = this;
}

function Nested(y) {
    this.y = y;
}

Hadi her şeyi bir araya getirelim Object adlı a.

var a = {
    x: 'a',
    circ: new Circ(),
    nested: new Nested('a')
};

Ardından, kopyalamak istiyoruz a adlı bir değişkene b ve değiştirin.

var b = a;

b.x = 'b';
b.nested.y = 'b';

Burada ne olduğunu biliyorsun, çünkü eğer bu büyük soruya bile gelemezsin.

console.log(a, b);

a --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

Şimdi bir çözüm bulalım.

JSON

Denediğim ilk girişim kullanıyordum JSON.

var b = JSON.parse( JSON.stringify( a ) );

b.x = 'b';
b.nested.y = 'b';

Çok fazla zaman harcamayın, alırsınız TypeError: Converting circular structure to JSON.

Yinelemeli kopya (kabul edilen "cevap")

Kabul edilen cevaba bir bakalım.

function cloneSO(obj) {
    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = cloneSO(obj[i]);
        }
        return copy;
    }

    // Handle Object
    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! Its type isn't supported.");
}

İyi görünüyor, değil mi? Nesnenin yinelemeli bir kopyasıdır ve diğer türleri de kullanır. Dateama bu bir gereklilik değildi.

var b = cloneSO(a);

b.x = 'b';
b.nested.y = 'b';

Özyineleme ve circular structures birlikte iyi çalışmıyor ... RangeError: Maximum call stack size exceeded

yerli çözüm

İş arkadaşımla tartıştıktan sonra patronum ne olduğunu sordu ve basit bir şey buldu. çözüm bazı googling sonra. Denir Object.create.

var b = Object.create(a);

b.x = 'b';
b.nested.y = 'b';

Bu çözüm, bir süre önce Javascript'e eklendi ve hatta kolları circular structure.

console.log(a, b);

a --> Object {
    x: "a",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

... ve görüyorsunuz, iç içe geçmiş yapıyla çalışmadı.

doğal çözüm için polyfill

İçin bir polyfill var Object.create IE 8 gibi eski tarayıcıda. Mozilla tarafından tavsiye edilen bir şey ve elbette, mükemmel değil ve aynı sorunla sonuçlanıyor. yerli çözüm.

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

var b = clonePF(a);

b.x = 'b';
b.nested.y = 'b';

Ben koydum F kapsam dışında, neye bir göz atabiliriz instanceof bize söyler.

console.log(a, b);

a --> Object {
    x: "a",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> F {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> true

Aynı sorun yerli çözümama biraz daha kötü çıktı.

daha iyi (ama mükemmel değil) çözüm

Etrafında kazarken, benzer bir soru buldum (Javascript'te, derin bir kopyasını gerçekleştirirken, "bu" olan bir özellik nedeniyle bir döngüyü nasıl önleyebilirim?) Buna, ancak daha iyi bir çözüm ile.

function cloneDR(o) {
    const gdcc = "__getDeepCircularCopy__";
    if (o !== Object(o)) {
        return o; // primitive value
    }

    var set = gdcc in o,
        cache = o[gdcc],
        result;
    if (set && typeof cache == "function") {
        return cache();
    }
    // else
    o[gdcc] = function() { return result; }; // overwrite
    if (o instanceof Array) {
        result = [];
        for (var i=0; i<o.length; i++) {
            result[i] = cloneDR(o[i]);
        }
    } else {
        result = {};
        for (var prop in o)
            if (prop != gdcc)
                result[prop] = cloneDR(o[prop]);
            else if (set)
                result[prop] = cloneDR(cache);
    }
    if (set) {
        o[gdcc] = cache; // reset
    } else {
        delete o[gdcc]; // unset again
    }
    return result;
}

var b = cloneDR(a);

b.x = 'b';
b.nested.y = 'b';

Ve çıktıya bir bakalım ...

console.log(a, b);

a --> Object {
    x: "a",
    circ: Object {
        me: Object { ... }
    },
    nested: Object {
        y: "a"
    }
}

b --> Object {
    x: "b",
    circ: Object {
        me: Object { ... }
    },
    nested: Object {
        y: "b"
    }
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> false

Gereksinimler eşleştirildi, ancak yine de bazı küçük sorunlar var. instance arasında nested ve circ için Object.

Bir yaprağı paylaşan ağaçların yapısı kopyalanmayacak, iki bağımsız yaprak haline gelecek:

        [Object]                     [Object]
         /    \                       /    \
        /      \                     /      \
      |/_      _\|                 |/_      _\|  
  [Object]    [Object]   ===>  [Object]    [Object]
       \        /                 |           |
        \      /                  |           |
        _\|  |/_                 \|/         \|/
        [Object]               [Object]    [Object]

Sonuç

Yineleme ve önbellek kullanarak son çözüm, en iyi olmayabilir, ama bu bir gerçek nesnenin derin kopyası. Basit işler properties, circular structures ve nested objectama klonlarken onların örneğini dağıtacaktır.

http://jsfiddle.net/einfallstoll/N4mr2/


63



bu yüzden bu problemden kaçınmak için conlcusion var :) - mikus
Mıkuza kadar gerçek Sadece temel kullanım durumlarından daha fazlasını kapsayan şartname, evet. - Fabio Poloni
Yukarıda sunulan çözümlerin tamamının analizi, ancak yazarın çıkardığı sonuç, bu soruya çözüm bulunmadığını göstermektedir. - Amir Mog
JS'nin yerel klon işlevini içermemesi utanç vericidir. - l00k
En iyi cevapların arasında, bunun doğru olana yakın olduğunu hissediyorum. - KTU