欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

js深拷貝和淺拷貝的深入講解

 更新時間:2022年05月10日 15:53:32   作者:Jimmy_fx  
深拷貝和淺拷貝是面試中經常出現的,主要考察對基本類型和引用類型的理解深度,這篇文章主要給大家介紹了關于js深拷貝和淺拷貝的相關資料,需要的朋友可以參考下

淺拷貝

創(chuàng)建一個新的對象,來接受你要重新復制或引用的對象值。如果對象屬性是基本的數據類型,復制的就是基本類型的值給新對象;但如果屬性是引用數據類型,復制的就是內存中的地址,如果其中一個對象改變了這個內存中的地址,會影響到另一個對象。

實現方法

方法一:Object.assign

es6 中 object 的一個方法,用于 JS 對象的合并等,返回目標對象。它不會拷貝對象的繼承屬性和不可枚舉的屬性

let target = {};
let source = {a:{b:1}};
Object.assign(target,source)
console.log(taget) // {a:{b:1}}
target.a.b = 2;
console.log(taget) // {a:{b:2}}
console.log(source) // {a:{b:2}}

方法二:擴展運算符方式

/* 對象的拷貝 */
let obj = {a:1,b:{c:1}}
let obj2 = {...obj}
obj.a = 2
console.log(obj)  //{a:2,b:{c:1}}
console.log(obj2); //{a:1,b:{c:1}}
obj.b.c = 2
console.log(obj)  //{a:2,b:{c:2}} 
console.log(obj2); //{a:1,b:{c:2}}
/* 數組的拷貝 */
let arr = [1, 2, 3];
let newArr = [...arr]; 

方法三:concat和slice 淺拷貝數組

僅僅針對數組類型,都會返回一個新的數組對象。

concat 淺拷貝數組
let arr = [1, 2, 3];
let newArr = arr.concat();
newArr[1] = 100;
console.log(arr);  // [ 1, 2, 3 ]
console.log(newArr); // [ 1, 100, 3 ]

slice 淺拷貝數組
let arr = [1, 2, {val: 4}];
let newArr = arr.slice();
newArr[2].val = 1000;
console.log(arr);  //[ 1, 2, { val: 1000 } ]

深拷貝

將一個對象從內存中完整地拷貝出來一份給目標對象,并從堆內存中開辟一個全新的空間存放新對象,且新對象的修改并不會改變原對象,二者實現真正的分離。

實現方法

方法一:乞丐版(JSON.stringify和JSON.parse)

let obj1 = { a:1, b:[1,2,3] }
let str = JSON.stringify(obj1);
let obj2 = JSON.parse(str);
console.log(obj2);   //{a:1,b:[1,2,3]} 
obj1.a = 2;
obj1.b.push(4);
console.log(obj1);   //{a:2,b:[1,2,3,4]}
console.log(obj2);   //{a:1,b:[1,2,3]}

缺陷:

  • 拷貝的對象的值中如果有函數、undefined、symbol 這幾種類型,經過 JSON.stringify 序列化之后的字符串中這個鍵值對會消失
  • 拷貝 Date 引用類型會變成字符串
  • 無法拷貝不可枚舉的屬性
  • 無法拷貝對象的原型鏈
  • 拷貝 RegExp 引用類型會變成空對象
  • 對象中含有 NaN、Infinity 以及 -Infinity,JSON 序列化的結果會變成 null

手寫遞歸實現

基礎版

 let obj = {a:{b:1}};
 function deepClone(obj){
  let cloneObj = Object.prototype.toString.call(obj) === "[object Array]" ? [] : {};
   for(let key in obj){
     if(typeof obj[key]=== "object" && obj !== null){
       cloneObj[key] = deepClone(obj[key])
     }else{
       cloneObj[key] = obj[key]
     }
   }
   return cloneObj;
 }
 let obj2 = deepClone(obj);
 obj2.a.b = 33
 console.log("obj",obj) // {a:{b:1}}
 console.log("obj2",obj2) // {a:{b:33}}

缺陷:  

  • 不能復制不可枚舉的屬性以及 Symbol 類型  
  • 這種方法只是針對普通的引用類型的值做遞歸復制,而對于 Array、Date、RegExp、Error、Function 這樣的引用類型并不能正確地拷貝
  • 對象的屬性里面成環(huán),即循環(huán)引用沒有解決

改進版

const isComplexDataType = obj => (typeof obj === 'object' || typeof obj === 'function') && (obj !== null)
const deepClone = function (obj, hash = new WeakMap()) {
  if (obj.constructor === Date) 
  return new Date(obj)       // 日期對象直接返回一個新的日期對象
  if (obj.constructor === RegExp)
  return new RegExp(obj)     //正則對象直接返回一個新的正則對象
  //如果循環(huán)引用了就用 weakMap 來解決
  if (hash.has(obj)) return hash.get(obj)
  let allDesc = Object.getOwnPropertyDescriptors(obj)
  //遍歷傳入參數所有鍵的特性
  let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc)
  //繼承原型鏈
  hash.set(obj, cloneObj)
  for (let key of Reflect.ownKeys(obj)) { 
    cloneObj[key] = (isComplexDataType(obj[key]) && typeof obj[key] !== 'function') ? deepClone(obj[key], hash) : obj[key]
  }
  return cloneObj
}

手寫深拷貝參考:

http://www.dbjr.com.cn/article/247540.htm

http://www.dbjr.com.cn/article/247544.htm

其他實現方法

lodash庫的_.cloneDeep方法,jQuery.extend()方法

FAQ:賦值和深淺拷貝的區(qū)別

注意:前提都是針對引用類型

賦值

當我們把一個對象賦值給一個新的變量時,賦的其實是該對象的在棧中的地址,而不是堆中的數據。也就是兩個對象指向的是同一個存儲空間,無論哪個對象發(fā)生改變,其實都是改變的存儲空間的內容,因此,兩個對象是聯動的。

let a = {name:'jimmy',b:{age:12}}
let b = a;
b.name = 'chimmy';
b.b.age = 21;
console.log(a) //  {name:'chimmy',b:{age:21}}
console.log(b) //  {name:'chimmy',b:{age:21}}

淺拷貝

重新在堆中創(chuàng)建內存,拷貝前后對象的基本數據類型互不影響,但拷貝前后對象的引用類型因共享同一塊內存,會相互影響。

let a = {name:'jimmy',b:{age:12}}
let b = {...a};
b.name = 'chimmy';
b.b.age = 21;
console.log(a) //  {name:'jimmy',b:{age:21}}
console.log(b) //  {name:'chimmy',b:{age:21}}

深拷貝

將一個對象從內存中完整地拷貝出來一份給目標對象,并從堆內存中開辟一個全新的空間存放新對象,且新對象的修改并不會改變原對象,二者實現真正的分離。

let a = {name:'jimmy',b:{age:12}}
let b = {...a};
b.name = 'chimmy';
b.b.age = 21;
console.log(a) //  {name:'jimmy',b:{age:12}}
console.log(b) //  {name:'chimmy',b:{age:21}}

總結

到此這篇關于js深拷貝和淺拷貝的文章就介紹到這了,更多相關js深拷貝和淺拷貝內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • window.location.href和window.open窗口跳轉區(qū)別解析

    window.location.href和window.open窗口跳轉區(qū)別解析

    這篇文章主要為大家介紹了window.location.href和window.open 跳轉區(qū)別解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-07-07
  • countUp.js實現數字動態(tài)變化效果

    countUp.js實現數字動態(tài)變化效果

    這篇文章主要為大家詳細介紹了countUp.js實現數字動態(tài)變化效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • JS實現隨機抽取三人

    JS實現隨機抽取三人

    這篇文章主要為大家詳細介紹了JS實現隨機抽取三人,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • webpack-dev-server搭建本地服務器的實現

    webpack-dev-server搭建本地服務器的實現

    當我們使用webpack打包時,發(fā)現每次更新了一點代碼,都需要重新打包,我們希望本地能搭建一個服務器,本文就介紹如何使用webpack-dev-server搭建本地服務器,感興趣的可以了解一下
    2021-07-07
  • 原生js實現日期計算器功能

    原生js實現日期計算器功能

    這篇文章主要為大家詳細介紹了原生js實現日期計算器功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • 移動端日期插件Mobiscroll.js使用詳解

    移動端日期插件Mobiscroll.js使用詳解

    這篇文章主要為大家詳細介紹了移動端日期插件Mobiscroll.js的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • 關于JavaScript中var聲明變量作用域的推斷

    關于JavaScript中var聲明變量作用域的推斷

    這個問題其實之前困擾了我很久。如今終于想明白了,特來分享,如果有錯誤的地方,請幫忙指正,我會隨時回來修正滴。
    2010-12-12
  • javascript使用appendChild追加節(jié)點實例

    javascript使用appendChild追加節(jié)點實例

    這篇文章主要介紹了javascript使用appendChild追加節(jié)點的方法,實例分析了appendChild()函數增加結點的使用技巧,需要的朋友可以參考下
    2015-01-01
  • 小程序實現側滑刪除功能

    小程序實現側滑刪除功能

    這篇文章主要為大家詳細介紹了小程序實現側滑刪除功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • Js 隨機數產生6位數字

    Js 隨機數產生6位數字

    Js隨機產生6為數字的代碼,需要的朋友可以參考下。
    2010-05-05

最新評論