Rumah >hujung hadapan web >tutorial js >Kaedah pelaksanaan kemahiran JavaScript deep clone_javascript

Kaedah pelaksanaan kemahiran JavaScript deep clone_javascript

WBOY
WBOYasal
2016-05-16 15:14:441391semak imbas

Terdapat jenis corak penggunaan semula kod yang dipanggil "corak sifat menyalin". Apabila kita memikirkan penggunaan semula kod, kemungkinan besar kita memikirkan pewarisan kod, tetapi penting untuk mengingati matlamat utama - kita mahu menggunakan semula kod. Warisan hanyalah satu cara untuk mencapai penggunaan semula kod, bukan satu-satunya cara. Menyalin sifat juga merupakan corak penggunaan semula, yang berbeza daripada warisan. Dalam corak ini, objek akan memperoleh ahli daripada objek lain dengan hanya menyalinnya. Sesiapa sahaja yang telah menggunakan jQuery tahu bahawa ia mempunyai kaedah $.extend() Selain melanjutkan pemalam pihak ketiga, ia juga boleh digunakan untuk menyalin atribut. Mari kita lihat kod pelaksanaan fungsi extend() (perhatikan bahawa ini bukan kod sumber jQuery, hanya contoh mudah):

function extend(parent, child) {
var i;
//如果不传入第二参数child
//那么就创建一个新的对象
child = child || {}; 
//遍历parent对象的所有属性
//并且过滤原型上的属性
//然后将自身属性复制到child对象上
for(i in parent) {
if(parent.hasOwnProperty(i)) {
child[i] = parent[i];
}
}
//返回目标对象child
return child;
} 

Kod di atas ialah pelaksanaan yang mudah, ia hanya melintasi ahli objek induk dan menyalinnya ke objek anak. Mari ujinya menggunakan kaedah extend() di atas:

var dad = {name: "Adam"};
var kid = extend(dad);
console.log(kid.name); //Adam 

Kami mendapati bahawa kaedah extend() sudah boleh berfungsi seperti biasa. Tetapi ada masalah yang diberikan di atas adalah klon cetek. Apabila menggunakan salinan cetek, jika anda menukar sifat objek kanak-kanak, dan harta itu menjadi objek, maka operasi ini juga akan mengubah suai objek induk Dalam banyak kes, ini bukan hasil yang kita inginkan. Pertimbangkan perkara berikut:

var dad = {
counts: [1, 2, 3],
reads: {paper: true}
};
var kid = extend(dad) //调用extend()方法将dad的属性复制到kid上面
kid.counts.push(4); //把4追加到kid.counts数组里面
console.log(dad.counts); //[1, 2, 3, 4] 

Melalui contoh di atas, kita akan mendapati bahawa selepas mengubah suai atribut kid.counts (menambah elemen 4 padanya), dad.counts juga akan terjejas. Ini kerana apabila menggunakan salinan cetek, memandangkan objek itu dihantar melalui rujukan, iaitu, kid.counts dan dad.counts menghala ke tatasusunan yang sama (atau dalam ingatan, mereka menghala ke alamat timbunan yang sama).

Seterusnya, mari kita ubah suai fungsi extend() untuk melaksanakan penyalinan dalam. Apa yang perlu kita lakukan ialah menyemak setiap atribut objek induk, dan jika atribut itu menjadi objek, kemudian salin secara rekursif atribut objek tersebut. Selain itu, anda juga perlu mengesan sama ada objek ialah tatasusunan Ini kerana kaedah penciptaan literal tatasusunan adalah berbeza daripada kaedah penciptaan literal objek yang pertama ialah [] dan yang terakhir ialah {}. Untuk mengesan tatasusunan, anda boleh menggunakan kaedah Object.prototype.toString() Jika ia adalah tatasusunan, ia akan mengembalikan "[object Array]". Mari kita lihat fungsi extend() versi salinan dalam:

function extendDeep(parent, child) {
child = child || {};
for(var i in parent) {
if(parent.hasOwnProperty(i)) {
//检测当前属性是否为对象
if(typeof parent[i] === "object") {
//如果当前属性为对象,还要检测它是否为数组
//这是因为数组的字面量表示和对象的字面量表示不同
//前者是[],而后者是{}
child[i] = (Object.prototype.toString.call(parent[i]) === "[object Array]") ? [] : {};
//递归调用extend
extendDeep(parent[i], child[i]);
} else {
child[i] = parent[i];
}
}
}
return child;
} 

Baiklah, fungsi salinan dalam telah ditulis Mari kita uji untuk melihat sama ada ia boleh berfungsi seperti yang diharapkan, iaitu sama ada salinan dalam boleh dicapai:

var dad = {
counts: [1, 2, 3],
reads: {paper: true}
};
var kid = extendDeep(dad);
//修改kid的counts属性和reads属性
kid.counts.push(4);
kid.reads.paper = false;
console.log(kid.counts); //[1, 2, 3, 4]
console.log(kid.reads.paper); //false
console.log(dad.counts); //[1, 2, 3]
console.log(dad.reads.paper); //true 

Melalui contoh di atas, kita dapati bahawa walaupun kid.counts dan kid.reads objek kanak-kanak diubah suai, ayah.counts dan kid.reads objek ibu bapa tidak berubah, jadi tujuan kita tercapai.

Berikut ialah ringkasan idea asas untuk melaksanakan salinan mendalam:

1. Semak sama ada atribut semasa ialah objek

2. Oleh kerana tatasusunan ialah objek khas, adalah perlu untuk mengesan sama ada atribut itu ialah tatasusunan jika ia adalah objek.

3. Jika ia adalah tatasusunan, buat [] tatasusunan kosong, jika tidak, buat {} objek kosong dan tetapkan ia kepada sifat semasa objek anak. Kemudian, fungsi extendDeep dipanggil secara rekursif.

Contoh di atas menggunakan kaedah salinan dalam yang dilaksanakan oleh kami sendiri menggunakan algoritma rekursif. Malah, dua kaedah yang disediakan oleh objek JSON baharu dalam ES5 juga boleh mencapai penyalinan mendalam, iaitu JSON.stringify() dan JSON.parse(); yang pertama digunakan untuk menukar objek kepada rentetan, dan yang terakhir digunakan untuk menukar rentetan Tukar kepada objek. Di bawah ini kami menggunakan kaedah ini untuk melaksanakan fungsi salinan dalam:

function extendDeep(parent, child) {
var i,
proxy;
proxy = JSON.stringify(parent); //把parent对象转换成字符串
proxy = JSON.parse(proxy) //把字符串转换成对象,这是parent的一个副本
child = child || {};
for(i in proxy) {
if(proxy.hasOwnProperty(i)) {
child[i] = proxy[i];
}
}
proxy = null; //因为proxy是中间对象,可以将它回收掉
return child;
} 

Berikut ialah contoh ujian:

var dad = {
counts: [1, 2, 3],
reads: {paper: true}
};
var kid = extendDeep(dad);
//修改kid的counts属性和reads属性
kid.counts.push(4);
kid.reads.paper = false;
console.log(kid.counts); //[1, 2, 3, 4]
console.log(kid.reads.paper); //false
console.log(dad.counts); //[1, 2, 3]
console.log(dad.reads.paper); //true 

Ujian mendapati ia juga mencapai penyalinan mendalam. Biasanya disyorkan untuk menggunakan kaedah yang terakhir, kerana JSON.parse dan JSON.stringify ialah fungsi terbina dalam dan akan diproses dengan lebih cepat. Di samping itu, kaedah sebelumnya menggunakan panggilan rekursif Kita semua tahu bahawa rekursi adalah algoritma yang agak tidak cekap.

Ini semua tentang kaedah pelaksanaan klon dalam JavaScript saya harap ia akan membantu anda!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn