淺拷貝深拷貝復習

背景
  • 深拷貝現在也是越來越容易被用上了,但是我對這方面還是有點不熟,特此總結下。

一、淺拷貝

1、直接遍歷

var array = [1, 2, 3, 4];function copy (array) {   let newArray = []   for(let item of array) {      newArray.push(item);   }   return  newArray;}var copyArray = copy(array);copyArray[0] = 100;console.log(array); // [1, 2, 3, 4]console.log(copyArray); // [100, 2, 3, 4]
  • 此方法如果元素是引用類型,改變新數組引用類型元素也會改變原數組的引用類型元素。

  • 遍歷對象也是一樣的都是淺拷貝:

let obj2 = {    name: "yehuozhili",    job: "programmer"}let  copyObj={}for(i in obj2){    copyObj[i]=obj2[i]}copyObj.name="業火之理"console.log(copyObj);console.log(obj2);

2、剩余運算符

let obj2 = {    name: "yehuozhili",    job: "programmer"}let copyObj2 = { ...obj2 }copyObj2.name = "業火之理"console.log(obj2.name)console.log(copyObj2.name) 
  • 數組同理,都是淺拷貝。

3、數組方法

  • 數組方法有這些:

  • slice方法不寫參數就是把array全部拷貝copyArray = array.slice();

  • concat一般用于連接2個數組,如果不寫參數就是和空連接,相當于復制copyArray = array.concat()

  • map一般用來迭代用的copyArray=array.map((item)=>item)相當于對原數組不做處理給新數組。

  • filter一般是返回true或者false:copyArray=array.filter(()=>true)相當于所有元素保留。

  • 以上所有方法全部是淺拷貝,對引用對象改動會改動原對象。

4、對象方法

  • 對象方法有這些:

  • Object.assign這個方法跟concat有點像copyObj2= Object.assign({},obj2)如果相同屬性會被替換。

二、深拷貝

1、Json.parse+Json.stringify

  • 用法copyObj = JSON.parse(JSON.stringify(obj))相當于直接轉成字符串再由json解析成對象,但這個方法有幾個缺點:

  • 這個方法不能轉函數、日期、正則等等。所以選擇此方法考慮對象里是否可能存在這些。

2、自己手寫深拷貝

 function deepCopy(obj){    //只能是對象或者array 其余返回    if(typeof obj==="object"&& obj!==null){        //如果是對象,還可能是日期正則        if(obj instanceof RegExp){            return new RegExp(obj)        }        if(obj instanceof Date){            return new Date(obj)        }        let newObj = new obj.constructor;        for (let i in obj){            if(obj.hasOwnProperty(i)){//如果有個函數a 它a.prototype.b="xx" 那么不加這個會把b也給迭代出來               newObj[i]=deepCopy(obj[i])            }        }        return newObj    }else{        return obj    } }let arr = [1,2,3,[1,2,3]]let a = deepCopy(arr)a[3][1]=4;console.log(a);console.log(arr);
  • 這個實現不難,有2個關鍵點

  • 1、這個新對象直接拿傳入對象的constructor生成,這個操作比較6。

  • 2、就是大家都知道的遞歸,所以在前面類型判斷時候如果不是引用類型,全部返回原樣,是引用類型,再判斷是不是一些特殊的,是特殊的就生成個新的,不是特殊的就迭代遞歸。

3、使用loadash

  • loadash里面有個方法叫clonedeep,我大概看了一下源碼,里面對各種類型判斷的很充分,比我們自己手寫的類型判斷多多了。

var objects = [{ "a": 1 }, { "b": 2 }]; var deep = _.cloneDeep(objects);console.log(deep[0] === objects[0]);// => false

4、使用immutable.js

  • immutable的數據類型實際發生變化,這個原理有點復雜,相當于重新把你的對象生成一個靠路徑查找的樹,有點像以前數據結構學的哈夫曼樹。就是把所有鍵,就算你的鍵不是數組,變成一個32位的樹,然后通過位運算進行查找和改動值。

  • immutable的好處就是只有改動的地方替換,不改動的話就只拿過來引用,像淺拷貝一樣,但是你改了引用的東西,他就拿新的來替換掉這個引用。在數據量大的情況下性能會有提高。否則每層遞歸拷出來非常浪費性能。

import { Map} from "immutable";let a = Map({  select: "users",  filter: Map({ name: "Cam" })})let b = a.set("select", "people");a === b; // falsea.get("filter") === b.get("filter"); // true
  • 使用方法也很簡單,就是找個對象套到map里,然后set就代表設置,get代表取值。

  • 上面那個例子可以發現引用類型不變的情況下,引用的都是同一個東西,但是他們實際上不是一個對象。

  • 這個東西叫immutable就是想讓放入的東西不可變,而你變了之后拿出來的是另一個對象。

5.使用immer.js

  • 跟別人吹牛時了解到這個庫,據說是immutable.js的精簡版,我也沒咋看,使用方法也挺簡單:

import produce from "immer"let currentState = {  a: [],  p: {    x: 1  }}let nextState = produce(currentState, (draft) => {  draft.a.push(2);})currentState.a === nextState.a; // falsecurrentState.p === nextState.p; // true

免責聲明:本文僅代表文章作者的個人觀點,與本站無關。其原創性、真實性以及文中陳述文字和內容未經本站證實,對本文以及其中全部或者部分內容文字的真實性、完整性和原創性本站不作任何保證或承諾,請讀者僅作參考,并自行核實相關內容。

http://image99.pinlue.com/thumb/img_jpg/ARV0Z4r30iavQbfKLzEIyIu5m6dRJdwNKZQRW1SOJfScBib0AzcU15PHyAGrn2Qv1QrTfDmvVE6lD7fImFoicLDyw/0.jpeg
我要收藏
贊一個
踩一下
分享到
?
分享
評論
首頁
竞彩网足球