# 淺拷貝與深拷貝 ## 為什麼需要這個?是為解決什麼問題? > 解決物件/陣列的拷貝問題 * 各自的使用場景 * 淺拷貝→當今天資料只有一層時,使用淺拷貝可以更輕量、不消耗太多資源的進行拷貝,它只複製最外層的結構,而不涉及內部對象的複製,這樣可以節省時間和資源 * 深拷貝→我們需要一個完全獨立的副本而不想修改到原始資料時,可以使用深拷貝 狀況一、物件沒有被實際拷貝 ```javascript let a = [1,2] let b = a // 沒有建立新物件,參考到同一個物件實體 b[0]=3 console.log(a)//[3,2] ``` 狀況二、物件拷貝→兩物件之間無關連性了 ```javascript let a = [1,2] let b = [...a] // 建立新物件,並複製原物件的資料 b[0]=3 console.log(a)//[1,2] ``` ## 淺拷貝 Shallow copy > 僅「真正」拷貝物件的第一層資料 * 僅第一層會是不同的參考 * 常見的拷貝工具都是淺拷貝 ```javascript let a = { x:1, y:2, data:[3,4,5] } let b = {...a} let c = Object.assign([],a) b.data[0] = 30 console.log(a.data[0]) // 30 →原本的 a 被改變了 ``` ## 深拷貝 Deep copy > 完全拷貝物件底下「所有」層次的資料 > 建立兩個完全獨立的物件實體 ### 方法一:JSON.parse(JSON.stringify(...)) * 使用 JS 內建方法 JSON.stringify() 將物件字串化(序列化 Serialize) * 使用JSON.parse() 根據字串化的資料重新建立物件結構,完成深拷貝 ```javascript let a = { x:1, y:2, data:[3,4,5] } let b =JSON.parse(JSON.stringify(a)) b.data[0] = 30 console.log(a.data[0]) // 3 →原本的 a 沒有被改變了 ``` #### ==JSON方法的限制== * 無法拷貝不能字串化的資料 * 無法拷貝函式或是 symbol 等資料 ### 方法二:structuredClone 使用 JS 內建方法 structuredClone ```javascript let a = { x:1, y:2, data:[3,4,5] } let b = structuredClone(a) b.x = 200 console.log("a",a.x)//1 console.log("b",b.x)//200 ``` ### 方法三:遞迴 建立 deepCopy function 思考: 1. 利用 typeof 判斷傳進來的物件是否為 object 2. 若不是,代表沒有需要拆解的第二層資料→return 3. 若是,繼續呼叫 deepCopy ```javascript function deepCopy(obj){ // 1.檢查是否為物件,如果不是,直接返回 if(typeof obj !== "object"&& obj !== null){ return } // 2.創建一個新的空物件或陣列,根據原始物件的類型 const newObj = Array.isArray(obj):[]?{} // 3.遞迴複製原始物件的每個屬性或元素 for(let key in obj){ // 進行拷貝(單維的 shallow copy 會建立兩個實體) // js object bracket notation // const c = {x:10,y:20} // console.log(c["y"])//20 newObj[key] = deepCopy(obj[key]) } return newObj } let a = { x:1, y:2, data:[3,4,5] } let b =deepCopy(a); b.data[0] = 30 console.log(a.data[0] )// 3 ``` 完成深拷貝!