使用js實現復制功能
本文實例為大傢分享瞭使用js實現復制功能的具體代碼,供大傢參考,具體內容如下
復制
1.遍歷復制(for in)
特征:不修改引用關系(原來的屬性還在),僅能復制字符屬性,Symbol不能復制,不可枚舉屬性不能復制,原型鏈不能復制。淺復制
2.JOSN.parse(JSON.stringify(obj)) 轉換復制
特征:修改引用關系(相當於創建一個新的對象,不再擁有原來的屬性),僅能復制字符屬性,Symbol不能復制,不可枚舉屬性不能復制,原型鏈不能復制,函數和其他類型不能復制。深復制
3.{…obj}解構賦值復制
特征:修改引用關系,Symbol和函數都能復制,不可枚舉屬性和原型鏈都不能復制。淺復制
4.Object.assign()對象復制
特征:不修改引用關系,可以復制屬性、方法、Symbol類型,不可枚舉屬性和原型鏈都不能復制。淺復制
深復制**
1.使用defineProperty***
function cloneObject(source,target){ if(source === null||source === undefined) return source; if(source===document) return; //判斷target是不是繼承對象的實例,是不是引用類型(null,undefined,Boolean,string,number都不是引用類型) if(!Object.prototype.isPrototypeOf(target)){ //判斷源對象是不是dom元素 if(HTMLElement.prototype.isPrototypeOf(source)){ //創建dom元素 target = document.createElement(source.nodeName); }else if(source.constructor === RegExp){ // 任何正則表達式都有source和flags,source是正則內容,flags是正則修飾符 // 因為這兩個屬性都是隻讀屬性,不能寫入,必須通過構造函數創建時帶入 target = new RegExp(source.source,source.flags); }else if(source.constructor === Date){ // 日期對象在創建的對象中將原有的日期對象放入,可以讓當前日期對象變為原有日期對象的值,但是沒有引用關系 targer = new Date(source); }else if(source.constructor === Function){ // 復制函數,通過正則表達式將函數中的參數以及函數體內容提取到數組中,然後通過new Function()創建 var arr = source.toString().replace(/\n|\r/g,"").trim().match(/\((.*?)\)\s*\{(.*)\}/).slice(1); target = new Function(arr[0].trim(),arr[1]); }else if(source.constructor === Set){ // set類型,在處理時,new Set時可以帶入數組,因此我們將原有set的列表強轉為數組,並且將這個強轉後的數組復制給新數組 target = new Set(cloneObject(Array.from(source.values()))); }else if(source.constructor === Map){ target = new Map(); // 如果是map類型,遍歷map中每個元素 for(var [key,value] of source.entries()){ // 如果key是引用類型, if(Object.prototype.isPrototypeOf(key)){ // 如果value引用類型,則將key和value分別做復制,並且將返回的結果放在map中 if(Object.prototype.isPrototypeOf(value)){ target.set(cloneObject(key),cloneObject(value)); }else{ //如果value不是引用類型,隻將key復制,並且放入map target.set(cloneObject(key),value); } }else{ // 這是key不是引用類型時 if(Object.prototype.isPrototyeOf(value)){ target.set(key,cloneObject(value)); }else{ target.set(key,value); } } } } else{ //除瞭null和undefined,其他類型都有constructor。任何對象的constructor都是它的類型,利用其constructor創建對象 //通過對象類型的反射創建新的同類型對象 target = new source.constructor(); } } //獲取對象的所有字符屬性名和Symbol屬性名的數組 var names = Object.getOwnPropertyName(source).concat(Object.getOwnPropertySymbols(source)); for(var i = 0;i < names.lenght; i++){ // 如果當前復制的是函數,並且這個函數的屬性是prototype,那麼這個屬性不復制,否則會死循環 if(source.constructor === Function&&names[i] === "prototype") continue; // 獲取當前屬性名的描述對象 var desc = Object.getOwnPropertyDescriptor(source,names[i]); // 這個描述對象的值如果是引用類型 if(Object.prototype.isPrototypeOf(desc.value)){ // 根據需要將源對象的描述內容設置給當前目標對象相同屬性名的描述內容,及值付為剛才創建相同類型的對象 Object.defineProperty(target,names[i],{ enumerable:desc.enumerable, configurable:desc.configurable, writable:desc.writable, value:cloneObject(desc.value) }); }else{ //如果描述的對象的值不是引用類型,直接將描述對象設置給目標對象的這個屬性 Object.defineProperty(target,names.desc); } } return target; } //原型.isPrototypeOf(對象)。對象裡面是不是擁有xx的原型 //反射:通過對象
2.使用JSON對象實現深復制
使用**JSON.parse(str)**可以將字符串轉換成對象;
使用**JSON.stringify(obj)**將對象轉換成對象形式的字符串,其中無法轉換對象中的方法,可以考慮先將對象中的方法使用toString()轉為字符串,然後再轉換使用JSON.stringify(obj);
*使用**JSON.parse(str)**可以將字符串轉換成對象
var obj={ a:1, b:3, //ab復制不會隨其中一個的變化而變化 c:{ //c復制會隨其中一個的變化而變化,因為c屬於對象的地址引用關系 d:10, e:20 } }; var o1 = JSON.parse(JSON.stringify(obj)); //將obj復制給o1
3.使用遞歸實現深復制
結構僅限於對象。如果存在數組、正則、日期對象、dom對象則不能使用。
var obj = { a:1, b:2, c:{ a:1, b:2, c:{ a:1, b:2, } } } //函數定義參數時,註意必要參數寫在前面,非必要參數寫在後面 function cloneObj(source,target){ if(target === undefined) target = {}; for(var prop in source){ //如果 if(typeof source[prop] === "object" && source[prop] != null){ target[prop] = {}; cloneObj(source[prop],target[prop]); }else{ target[prop] = source[prop]; } } return target; }
以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 詳解JSON.parse和JSON.stringify用法
- 一文徹底理解js原生語法prototype,__proto__和constructor
- JS中的Error對象及使用JSON.stringify()序列化Error問題
- JavaScript深拷貝的幾種實現方法實例
- JavaScript JSON.stringify()的使用總結