最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JS深拷貝的4種實(shí)現(xiàn)方法

 更新時(shí)間:2023年10月13日 09:50:03   作者:samllplum  
對(duì)于js中的對(duì)象的深拷貝在項(xiàng)目的開發(fā)中比較常用到,本文就來介紹一下JS深拷貝的4種實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的可以了解一下

淺拷貝與深拷貝

淺拷貝是創(chuàng)建一個(gè)新對(duì)象,這個(gè)對(duì)象有著原始對(duì)象屬性值的拷貝。如果屬性是基本類型,拷貝的就是基本類型的值,如果屬性是引用類型,拷貝的是內(nèi)存地址 。

如果不進(jìn)行深拷貝,其中一個(gè)對(duì)象改變了對(duì)象的值,就會(huì)影響到另一個(gè)對(duì)象的值。 深拷貝是將一個(gè)對(duì)象從內(nèi)存中完整的拷貝一份出來,從堆內(nèi)存中開辟一個(gè)新的區(qū)域存放新對(duì)象,且修改新對(duì)象不會(huì)影響原對(duì)象。

1、JSON.parse(JSON.stringify(obj))序列化和反序列

先將需要拷貝的對(duì)象進(jìn)行JSON字符串化,然后再pase解析出來,賦給另一個(gè)變量,實(shí)現(xiàn)深拷貝。

let a = {a:1,b:2}
let b = JSON.parse(JSON.stringify(a))
a.a = 11

1.1 JSON.parse(JSON.stringify(obj))深淺拷貝的缺陷

let a = {
    name: 'Jack',
    age: 18,
    hobbit: ['sing', {type: 'sports', value: 'run'}],
    score: {
        math: 'A',
    },
    run: function() {},
    walk: undefined,
    fly: NaN,
    cy: null,
    date: new Date()
}
let b = JSON.parse(JSON.stringify(a))

取不到值為 undefined 的 key;如果對(duì)象里有函數(shù),函數(shù)無法被拷貝下來;無法拷貝copyObj對(duì)象原型鏈上的屬性和方法;對(duì)象轉(zhuǎn)變?yōu)?date 字符串。

2. Object.assign(target, source1, source2)

es6新增的方法,可用于對(duì)象合并,將源對(duì)象的所有可枚舉屬性,復(fù)制到目標(biāo)對(duì)象上。

var data = {
              a: "123",
              b: 123,
              c: true,
              d: [43, 2],
              e: undefined,
              f: null,
              g: function() {    console.log("g");  },
              h: new Set([3, 2, null]),
              i: Symbol("fsd"),
              k: new Map([    ["name", "張三"],    ["title", "Author"]  ])
        };
var newData = Object.assign({},data)
console.log(newData) 

可以看到這個(gè)API可以將源對(duì)象上的全部數(shù)據(jù)類型屬性值完全復(fù)制到一個(gè)新的對(duì)象上,這難道就是我們所尋找的最完美的深拷貝方式了嗎?答案是否,只能說是部分深拷貝,或者說就是淺拷貝,為什么這么說呢,接著往下看。

var test = {  name: '張三' }
var data = { 
              a: 123,
              b: test
            }
var newData = Object.assign({},data)
console.log(newData) 
// {  a: 123,  b: {    name: '張三'  }}
test.age = 18
console.log(newData)
// {  a: 123,  b: {    name: '張三',   age: 18  }}

結(jié)果很明顯,這種方式的拷貝,如果源目標(biāo)對(duì)象中某個(gè)屬性值是對(duì)另一個(gè)對(duì)象的引用,那么這個(gè)屬性的拷貝仍然是對(duì)引用的拷貝。 

3、普通遞歸函數(shù)實(shí)現(xiàn)深拷貝 

function deepClone(source) {
  if (typeof source !== 'object' || source == null) {
    return source;
  }
  const target = Array.isArray(source) ? [] : {};
  for (const key in source) {
    if (Object.prototype.hasOwnProperty.call(source, key)) {
      if (typeof source[key] === 'object' && source[key] !== null) {
        target[key] = deepClone(source[key]);
      } else {
        target[key] = source[key];
      }
    }
  }
  return target;
}

3.1、解決循環(huán)引用和symblo類型

function cloneDeep(source, hash = new WeakMap()) {
  if (typeof source !== 'object' || source === null) {
    return source;
  }
  if (hash.has(source)) {
    return hash.get(source);
  }
  const target = Array.isArray(source) ? [] : {};
  Reflect.ownKeys(source).forEach(key => {
    const val = source[key];
    if (typeof val === 'object' && val != null) {
      target[key] = cloneDeep(val, hash);
    } else {
      target[key] = val;
    }
  })
  return target;
}

4. 迭代遞歸方法(解決閉環(huán)問題)

function deepCopy(data, hash = new WeakMap()) {
      if(typeof data !== 'object' || data === null){
            throw new TypeError('傳入?yún)?shù)不是對(duì)象')
        }
      // 判斷傳入的待拷貝對(duì)象的引用是否存在于hash中
      if(hash.has(data)) {
            return hash.get(data)
        }
      let newData = {};
      const dataKeys = Object.keys(data);
      dataKeys.forEach(value => {
         const currentDataValue = data[value];
         // 基本數(shù)據(jù)類型的值和函數(shù)直接賦值拷貝 
         if (typeof currentDataValue !== "object" || currentDataValue === null) {
              newData[value] = currentDataValue;
          } else if (Array.isArray(currentDataValue)) {
             // 實(shí)現(xiàn)數(shù)組的深拷貝
            newData[value] = [...currentDataValue];
          } else if (currentDataValue instanceof Set) {
             // 實(shí)現(xiàn)set數(shù)據(jù)的深拷貝
             newData[value] = new Set([...currentDataValue]);
          } else if (currentDataValue instanceof Map) {
             // 實(shí)現(xiàn)map數(shù)據(jù)的深拷貝
             newData[value] = new Map([...currentDataValue]);
          } else { 
             // 將這個(gè)待拷貝對(duì)象的引用存于hash中
             hash.set(data,data)
             // 普通對(duì)象則遞歸賦值
             newData[value] = deepCopy(currentDataValue, hash);
          } 
       }); 
      return newData;
  }

比之前的1.0版本多了個(gè)存儲(chǔ)對(duì)象的容器WeakMap,思路就是,初次調(diào)用deepCopy時(shí),參數(shù)會(huì)創(chuàng)建一個(gè)WeakMap結(jié)構(gòu)的對(duì)象,這種數(shù)據(jù)結(jié)構(gòu)的特點(diǎn)之一是,存儲(chǔ)鍵值對(duì)中的健必須是對(duì)象類型。

  • 首次調(diào)用時(shí),weakMap為空,不會(huì)走上面那個(gè)if(hash.has())語句,如果待拷貝對(duì)象中有屬性也為對(duì)象時(shí),則將該待拷貝對(duì)象存入weakMap中,此時(shí)的健值和健名都是對(duì)該待拷貝對(duì)象的引用
  • 然后遞歸調(diào)用該函數(shù)
  • 再次進(jìn)入該函數(shù),傳入了上一個(gè)待拷貝對(duì)象的對(duì)象屬性的引用和存儲(chǔ)了上一個(gè)待拷貝對(duì)象引用的weakMap,因?yàn)槿绻茄h(huán)引用產(chǎn)生的閉環(huán),那么這兩個(gè)引用是指向相同的對(duì)象的,因此會(huì)進(jìn)入if(hash.has())語句內(nèi),然后return,退出函數(shù),所以不會(huì)一直遞歸進(jìn)棧,以此防止棧溢出。

總結(jié)

上述的幾種方式不管優(yōu)缺點(diǎn)如何,共同點(diǎn)是只能拷貝對(duì)象的可枚舉屬性,對(duì)于不可枚舉或者原型上的屬性,卻不能拷貝,但對(duì)于基本的使用來說,已經(jīng)足夠了。

到此這篇關(guān)于JS深拷貝的4種實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)JS深拷貝內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

台南县| 清流县| 建湖县| 石家庄市| 鹤壁市| 吉木萨尔县| 白水县| 株洲县| 德兴市| 青海省| 宝应县| 丹巴县| 黔江区| 江源县| 馆陶县| 内江市| 西吉县| 义乌市| 墨脱县| 云浮市| 灵台县| 丰都县| 繁峙县| 米泉市| 桐庐县| 松潘县| 天柱县| 敖汉旗| 防城港市| 泽州县| 沈丘县| 临夏市| 阳山县| 达尔| 会昌县| 新河县| 闽清县| 呈贡县| 苗栗市| 德州市| 惠来县|