Rumah  >  Soal Jawab  >  teks badan

Bagaimana untuk mengklon objek JavaScript dengan betul?

<p>Saya mempunyai objek <kod>x</code>. Saya mahu menyalinnya sebagai objek <kod>y</kod> supaya berubah kepada <kod>y</kod> Saya menyedari bahawa menyalin objek yang diperoleh daripada objek JavaScript terbina dalam akan mencipta sifat tambahan yang tidak diingini. Ini bukan masalah kerana saya menyalin salah satu objek binaan teks saya sendiri. </p> <p>Bagaimana untuk mengklon objek JavaScript dengan betul? </p>
P粉334721359P粉334721359393 hari yang lalu439

membalas semua(2)saya akan balas

  • P粉691958181

    P粉6919581812023-08-24 09:44:45

    Jika anda tidak menggunakan tarikh, fungsi, undefined, regExp atau Infinity dalam objek anda, baris yang sangat mudah ialah JSON.parse(JSON.stringify(objek))< /代码>:

    const a = {
      string: 'string',
      number: 123,
      bool: false,
      nul: null,
      date: new Date(),  // stringified
      undef: undefined,  // lost
      inf: Infinity,  // forced to 'null'
    }
    console.log(a);
    console.log(typeof a.date);  // Date object
    const clone = JSON.parse(JSON.stringify(a));
    console.log(clone);
    console.log(typeof clone.date);  // result of .toISOString()

    Ini berfungsi untuk semua jenis objek termasuk objek, tatasusunan, rentetan, boolean dan nombor.

    Juga lihat artikel ini tentang Pelayar Algoritma Klon Berstruktur , digunakan semasa menghantar mesej kepada/daripada pekerja. Ia juga termasuk fungsi pengklonan dalam.

    balas
    0
  • P粉122932466

    P粉1229324662023-08-24 00:44:32

    Dikemas kini 2022

    Terdapat standard JS baharu yang dipanggil Pengklonan Berstruktur. Ia berfungsi dalam banyak penyemak imbas (lihat Saya boleh menggunakannya).

    const clone = structuredClone(object);
    

    Jawapan lama

    Ia tidak akan menjadi mudah atau mudah untuk melakukan ini dengan mana-mana objek dalam JavaScript. Anda akan menghadapi masalah mendapatkan sifat yang salah daripada prototaip objek, yang sepatutnya kekal dalam prototaip dan bukannya disalin ke contoh baharu. Sebagai contoh, jika anda pergi ke kaedah Object.prototype 添加一个 clone 方法(如某些答案所述),则需要显式跳过该属性。但是,如果在 Object.prototype 或其他中间原型中添加了您不知道的其他附加方法怎么办?在这种情况下,您将复制不应该复制的属性,因此您需要使用 hasOwnProperty.

    Selain sifat yang tidak terhitung, anda juga menghadapi masalah yang lebih rumit apabila anda cuba menyalin objek dengan sifat tersembunyi. Sebagai contoh, dirujuk oleh prototype 是函数的隐藏属性。此外,对象的原型是通过属性 __proto__ , sifat ini juga disembunyikan dan tidak akan disalin oleh untuk/dalam gelung yang berulang ke atas sifat objek sumber. Saya rasa __proto__ mungkin khusus untuk jurubahasa JavaScript Firefox dan mungkin berbeza dalam penyemak imbas lain, tetapi anda mendapat idea itu. Tidak semuanya boleh dikira. Jika anda tahu nama harta tersembunyi anda boleh menyalinnya, tetapi saya tidak tahu cara untuk menemuinya secara automatik.

    Satu lagi halangan dalam mencari penyelesaian yang elegan ialah masalah menyediakan pewarisan prototaip dengan betul. Jika prototaip objek sumber ialah Object,则只需使用 {} 创建一个新的通用对象即可,但如果源对象的原型是 Object 的某个后代code>,那么您将丢失该原型中使用 hasOwnProperty ahli lain yang dilangkau oleh penapis, atau ahli lain yang berada dalam prototaip tetapi tidak dapat dikira pada mulanya. Satu penyelesaian mungkin adalah dengan memanggil harta pembina objek sumber untuk mendapatkan objek salinan awal dan kemudian menyalin sifat, tetapi anda masih tidak akan mendapat sifat yang tidak boleh dikira. Contohnya, objek Date menyimpan datanya sebagai ahli tersembunyi:

    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);
    Rentetan tarikh untuk

    d1 的日期字符串将比 d2 晚 5 秒。使一个 Date 与另一个相同的方法是调用 setTime 方法,但这是特定于 Dated1 akan lewat 5 saat daripada

    d2
    . Cara untuk menjadikan satu 🎜Tarikh sama dengan yang lain adalah dengan memanggil kaedah 🎜setTime, tetapi ini khusus untuk kelas 🎜Tarikh. Saya tidak fikir ada penyelesaian universal yang tidak mudah untuk masalah ini, walaupun saya gembira kerana tersilap! 🎜

    Apabila saya terpaksa melaksanakan salinan dalam am, saya akhirnya berkompromi dengan menganggap bahawa saya hanya perlu menyalin salinan biasa ObjectArrayDate、<代码>字符串、<代码>数字或<代码>布尔。最后 3 种类型是不可变的,因此我可以执行浅复制而不用担心它会发生变化。我进一步假设 ObjectArray dan sebarang elemen yang terkandung di dalamnya juga akan menjadi salah satu daripada 6 jenis mudah dalam senarai itu. Ini boleh dilakukan dengan kod seperti ini:

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

    Selagi data dalam objek dan tatasusunan membentuk struktur pokok, fungsi di atas adalah mencukupi untuk 6 jenis mudah yang saya nyatakan. Iaitu, data yang sama dalam objek dirujuk tidak lebih daripada sekali. Contohnya:

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

    Ia tidak akan mengendalikan sebarang objek JavaScript, tetapi ia mungkin cukup bagus untuk banyak tujuan, selagi anda tidak fikir ia hanya akan berfungsi dengan apa sahaja yang anda lemparkan kepadanya.

    balas
    0
  • Batalbalas