SORU
8 NİSAN 2009, ÇARŞAMBA


En zarif şekilde bir JavaScript clone itiraz

Bir nesne var x. Kopyalamak nesne y değişiklikler x değiştirme y gibi istiyorum.

JavaScript ile bunu yapmanın en zarif yolu nedir?

Edit: kopyalama nesneleri yerleşik JavaScript nesneleri türetilen ek, istenmeyen özellikler neden olacağını fark ettim. Bu, edebi-inşa kendi nesnelerden birini taklit ediyorum, çünkü bu bir sorun değil.

CEVAP
8 NİSAN 2009, ÇARŞAMBA


JavaScript herhangi bir nesne için bunu yapmak için basit veya kolay olmayacak. Yanlışlıkla prototip ve yeni örnek kopyalanan değil bırakılmalıdır nesnenin prototip niteliklerini tespit edilen sorun haline çalışacaktır. Örneğin, bazı cevaplar tasvir gibi Object.prototype clone bir yöntem ekleyerek, açıkça bu öznitelik atlamak gerekir. Peki ya diğer ek yöntemler Object.prototype veya diğer ara prototip eklenirse, biliyor musunuz? Bu durumda, hasOwnProperty yöntemi ile, yerel olmayan beklenmedik niteliklerini tespit etmek gerekir, bu yüzden mi, gerekmez öznitelikleri kopyalamak.

Olmayan sayısız özelliklerinin yanı sıra, özellikleri gizli nesneleri kopyalamaya çalıştığınızda zor bir sorunla karşılaşırsınız. Örneğin, prototype için fonksiyon gizli bir özellik. Ayrıca, bir nesnenin prototip niteliği ile de gizli, ve döngü için bir kaynak nesne nitelikleri üzerinden yineleme gönderilmez __proto__ başvurulan. __proto__ Firefox'un JavaScript yorumlayıcısı için özel olabilir ve bir şey diğer tarayıcılarda farklı olabilir, ama resmi olsun. Her şey sayısız. Eğer adını biliyorsanız gizli bir nitelik kopyalayabilirsiniz, ama bunu otomatik olarak keşfetmek için başka bir yol bilmiyorum.

Zarif bir çözüm arayışı içinde başka bir Budak prototip mirası doğru kurma sorunudur. Eğer kaynak nesne prototip Object, o zaman sadece oluşturma Yeni bir genel nesne ile {} işe yarar, ama eğer kaynak prototip bazı torunu Object sonra çıkacak eksik ek üyelerden prototip olan atladın kullanarak hasOwnProperty filtre veya ... ... prototip, ama sayısız değildi ilk başta. Bir çözüm kaynağı constructor özellik ilk kopya nesne nesne ve öznitelikleri kopyalayın aramak için olabilir, ama yine de olmayan sayısız nitelikleri olsun. Örneğin, Date bir nesne gizli bir üyesi olarak kendi veri depoları:

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

/* Wait for 5 seconds. */
var start = (new Date()).getTime();
while ((new Date()).getTime() - start < 5000);


var d2 = clone(d1);
alert("d1 = "   d1.toString()   "\nd2 = "   d2.toString());

d1 tarih dizesi d2 bunun arkasında 5 saniye olacak. Date başka bir yapmak için bir yol setTime yöntemini çağırarak, ama bu Date sınıf özgüdür. Yanılmaktan mutlu olurum ama bu sorun için kurşun geçirmez genel bir çözüm olduğunu sanmıyorum!

Ne zaman uygulamak için genel derin kopyalama sona erdi uzlaşarak farz ediyorum ki sadece kopyalamak gerekiyor bir düz Object, Array, Date, String, Number, ya Boolean. Son 3 tip değişmez, sığ bir kopyasını yapmak ve bunu dert değiştirme değil. Ben daha herhangi bir öğe Object Array içerdiği de bu listede 6 basit türlerinden biri olacağını düşünmüştüm. Bu kodu aşağıdaki gibi yapılabilir:

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şlevi yeterince bahsettim 6 basit türleri için çalışmak sürece, nesneleri veri ve ağaç yapısı oluşturmak diziler. Bu nesne aynı veri için birden fazla başvuru yok. Ö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 cylicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};
cylicGraph["right"] = cylicGraph;

Herhangi bir JavaScript nesnesi işlemek için mümkün olmayacaktır, ama birçok amaç için yeterli sadece bir iş olacağını kabul etmediğin sürece bunu atmak herhangi bir şey için olabilir.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • androidandme

    androidandme

    10 Mart 2009
  • David MeShow

    David MeShow

    10 EKİM 2006
  • thepoke64738

    thepoke64738

    17 HAZİRAN 2011