Pertanyaan Menyalin larik berdasarkan nilai dalam JavaScript


Saat menyalin larik dalam JavaScript ke larik lain:

var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d');  //Now, arr1 = ['a','b','c','d']

aku menyadari itu arr2 mengacu pada larik yang sama dengan arr1, bukan array baru yang independen. Bagaimana saya bisa menyalin array untuk mendapatkan dua array independen?


1335
2017-09-20 13:38


asal


Jawaban:


Gunakan ini:

var newArray = oldArray.slice();

Pada dasarnya, itu mengiris() operasi mengkloning array dan mengembalikan referensi ke array baru. Perhatikan juga bahwa:

Untuk referensi, string dan angka (dan bukan objek sebenarnya), slice menyalin referensi objek ke dalam array baru. Array asli dan baru mengacu pada objek yang sama. Jika objek yang direferensikan berubah, perubahan dapat dilihat pada array baru dan asli.

Primitif seperti string dan angka tidak dapat diubah sehingga perubahan string atau angka menjadi tidak mungkin.


2152
2017-09-20 13:41



Dalam Javascript, teknik deep-copy bergantung pada elemen-elemen dalam sebuah array.
Ayo mulai dari sana.

Tiga jenis elemen

Elemen dapat berupa: nilai literal, struktur literal, atau prototipe.

// Literal values (type1)
var booleanLiteral = true;
var numberLiteral = 1;
var stringLiteral = 'true';

// Literal structures (type2)
var arrayLiteral = [];
var objectLiteral = {};

// Prototypes (type3)
var booleanPrototype = new Bool(true);
var numberPrototype = new Number(1);
var stringPrototype = new String('true');
var arrayPrototype = new Array();
var objectPrototype = new Object(); # or "new function () {}"

Dari elemen-elemen ini kita dapat membuat tiga jenis array.

// 1) Array of literal-values (boolean, number, string) 
var type1 = [true, 1, "true"];

// 2) Array of literal-structures (array, object)
var type2 = [[], {}];

// 3) Array of prototype-objects (function)
var type3 = [function () {}, function () {}];

Teknik copy yang mendalam tergantung pada tiga tipe array

Berdasarkan jenis elemen dalam array, kita dapat menggunakan berbagai teknik untuk menyalin dalam.

Javascript deep copy techniques by element types

  • Larik nilai literal (tipe1)
    Itu myArray.splice(0), myArray.slice(), dan myArray.concat() teknik dapat digunakan untuk menyalin array dalam dengan nilai literal (boolean, angka, dan string) saja; di mana Slice memiliki kinerja yang lebih tinggi daripada Concat (http://jsperf.com/duplicate-array-slice-vs-concat/3).

  • Array dari literal-values ​​(tipe1) dan literal-structures (type2)
    Itu JSON.parse(JSON.stringify(myArray)) teknik dapat digunakan untuk menyalin nilai literal dalam (boolean, angka, string) dan struktur literal (array, objek), tetapi bukan objek prototipe.

  • Semua array (type1, type2, type3)
    JQuery $.extend(myArray) teknik dapat digunakan untuk menyalin-dalam semua tipe-array. Perpustakaan suka Menggarisbawahi dan Lo-dash menawarkan fungsi deep-copy yang serupa ke jQuery  $.extend(), namun memiliki kinerja yang lebih rendah. Lebih mengejutkan lagi, $.extend() memiliki kinerja yang lebih tinggi daripada JSON.parse(JSON.stringify(myArray)) teknik http://jsperf.com/js-deep-copy/15.
    Dan bagi pengembang yang menghindar dari pustaka pihak ketiga (seperti jQuery), Anda dapat menggunakan fungsi kustom berikut; yang memiliki kinerja lebih tinggi dari $ .extend, dan deep-copy semua array.

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

Jadi untuk menjawab pertanyaan ...

Pertanyaan 

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

Saya menyadari bahwa arr2 mengacu pada array yang sama dengan arr1, bukan a   array baru dan independen. Bagaimana saya bisa menyalin array untuk mendapatkan dua   array independen?

Menjawab 

Karena arr1 adalah larik nilai literal (boolean, angka, atau string), Anda dapat menggunakan teknik salinan dalam yang dibahas di atas, di mana slice memiliki kinerja tertinggi.

// Highest performance for deep copying literal values
arr2 = arr1.slice();

// Any of these techniques will deep copy literal values as well,
//   but with lower performance.
arr2 = arr1.splice(0);
arr2 = arr1.concat();
arr2 = JSON.parse(JSON.stringify(arr1));
arr2 = $.extend(true, [], arr1); // jQuery.js needed
arr2 = _.extend(arr1); // Underscore.js needed
arr2 = _.cloneDeep(arr1); // Lo-dash.js needed
arr2 = copy(arr1); // Custom-function needed - as provided above

363
2018-05-08 08:36



Tidak perlu jQuery ... Contoh Kerja

var arr2 = arr1.slice()

Ini menyalin array dari posisi awal 0 melalui ujung array.

Penting untuk dicatat bahwa ini akan bekerja seperti yang diharapkan untuk tipe primitif (string, angka, dll.), Dan juga menjelaskan perilaku yang diharapkan untuk tipe referensi ...

Jika Anda memiliki array tipe Referensi, katakanlah jenisnya Object. Array akan disalin, tetapi kedua array akan berisi referensi yang sama Object's. Jadi dalam hal ini akan tampak seperti array disalin oleh referensi meskipun array sebenarnya disalin.


146
2017-09-20 13:39



Anda dapat menggunakan spread array ... untuk menyalin array.

const itemsCopy = [...items];

Juga jika ingin membuat array baru dengan yang sudah ada menjadi bagian dari itu:

var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];

Spread array sekarang didukung di semua browser utama tetapi jika Anda membutuhkan dukungan yang lebih lama, gunakan typescript atau babel dan kompilasi ke ES5.

Info lebih lanjut tentang spread


136
2017-07-03 14:46



Sebuah alternatif untuk slice aku s concat, yang dapat digunakan dalam 2 cara. Yang pertama mungkin lebih mudah dibaca karena perilaku yang dimaksudkan sangat jelas:

var array2 = [].concat(array1);

Metode kedua adalah:

var array2 = array1.concat();

Cohen (dalam komentar) menunjukkan bahwa metode yang terakhir ini memiliki kinerja yang lebih baik.

Cara kerjanya adalah bahwa concat metode membuat array baru yang terdiri dari elemen-elemen dalam objek yang disebut diikuti oleh elemen-elemen dari setiap array yang dilewatkan ke sana sebagai argumen. Jadi ketika tidak ada argumen yang dilewatkan, itu hanya menyalin array.

Lee Penkman, juga di komentar, menunjukkan bahwa jika ada kesempatan array1 aku s undefined, Anda dapat mengembalikan larik kosong sebagai berikut:

var array2 = [].concat(array1 || []);

Atau, untuk metode kedua:

var array2 = (array1 || []).concat();

Perhatikan bahwa Anda juga dapat melakukan ini dengan slice: var array2 = (array1 || []).slice();.


67
2017-10-18 00:11



Ini adalah bagaimana saya melakukannya setelah mencoba banyak pendekatan:

var newArray = JSON.parse(JSON.stringify(orgArray));

Ini akan membuat salinan mendalam baru yang tidak terkait dengan yang pertama (bukan salinan dangkal).

Juga ini jelas tidak akan mengkloning acara dan fungsi, tetapi hal yang baik Anda dapat melakukannya dalam satu baris, dan itu dapat digunakan untuk segala jenis objek (array, string, angka, objek ...)


39
2018-04-23 13:32



Beberapa metode yang disebutkan bekerja dengan baik ketika bekerja dengan tipe data sederhana seperti angka atau string, tetapi ketika array berisi objek lain metode ini gagal. Ketika kita mencoba untuk melewati objek apa pun dari satu array ke array lain, ia dilewatkan sebagai referensi, bukan objek.

Tambahkan kode berikut di file JavaScript Anda:

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

Dan gunakan saja

var arr1 = ['val_1','val_2','val_3'];
var arr2 = arr1.clone()

Ini akan berhasil.


17
2017-12-12 16:22