ES6深拷贝函数封装

您所在的位置:网站首页 js深拷贝拷贝函数 ES6深拷贝函数封装

ES6深拷贝函数封装

#ES6深拷贝函数封装| 来源: 网络整理| 查看: 265

前置:WeakMap数据类型

Map与WeakMap区别:

Map的键名可以是任意类型({}、[]) WeakMap的键名只能是对象

例:从垃圾回收来感受WeakMap

 const oBtn1 = document.querySelector('#btn1')  const oBtn2 = document.querySelector('#btn1')  ​  oBtn1.addEventListener('click', handleClick1, false)  oBtn2.addEventListener('click', handleClick2, false)  ​  function handleClick1() {}  function handleClick2() {}  ​  oBtn1.remove() // 删除节点,但是不能回收事件回调函数  oBtn2.remove()  ​  // 必须使用这种方法删除回调  handleClick1 = null;  handleClick2 = null

使用WeakMap:

 const oBtn1 = document.querySelector('#btn1')  const oBtn2 = document.querySelector('#btn1')  ​  const oBtnMap = new WeakMap()  ​  // 将节点与回调绑定在一起,垃圾回收时一起被回收(键名键值一起回收)  // 键名是弱引用  oBtnMap.set(oBtn1, handleClick1)  oBtnMap.set(oBtn2, handleClick2)  ​  oBtn1.addEventListener('click', handleClick1, false)  oBtn2.addEventListener('click', handleClick2, false)  ​  function handleClick1() {}  function handleClick2() {}  ​  // oBtn1.remove() // 删除节点,但是不能回收事件回调函数  //oBtn2.remove()

换一个角度看,WeakMap的键名必须是对象,弱引用才有意义。

深拷贝函数封装

拷贝之前,需要先判断原始值(origin)的数据类型再进行下一步操作。

function当做静态数据类型,不做特殊处理。

1)关于null和undefined的判断:

 // null undefined  var a = undefined;  console.log(a == null); // true  console.log(a === null); // false

使用 origin === undefined 表达式就能判断origin是否为null和undefined值。

2)判断Date、RegExp类型数据:

 if (origin instanceof Date) {    return new Date(origin);  }  if (origin instanceof RegExp) {    return new RegExp(origin);  }

3)判断 {} 或 [] :

使用构造器

 const obj = {}  console.log(obj)

打印结果:

可以看到,字面量obj是通过其原型上的constructor使用new Object构造出来的,那么是否可以自己手动构造一个obj呢?

 const obj = {}  const newObj = new obj.constructor()  console.log(obj) // {}  newObj.a = 1  console.log(newObj); // {a:1}

同理,数组:

 const arr = []  const newArr = new arr.constructor()  console.log(arr);  newArr.push(1)  console.log(newArr);

知道这点,直接使用 const target = new origin.constructor() 生成一个新 {} 或 [] 即可,不用再判断了。

封装函数1  function deepClone(origin) {    if (origin === undefined || typeof origin !== 'object') { // 排除null、undefined、非object值      return origin;   }    if (origin instanceof Date) {      return new Date(origin);   }    if (origin instanceof RegExp) {      return new RegExp(origin);   }  ​    // [] -> [], {} -> {}, 不需要判断是对象还是数组    const target = new origin.constructor()  ​    for (let k in origin) {      if (origin.hasOwnProperty(k)) {        target[k] = deepClone(origin[k])     }   }  ​    return target;  } 测试1  var obj = {    name: 'yesmore',    age: 18,    info: {      hobby: ['travel', 'piano', {        a: 1     }],      career: {        teacher: 4,        engineer: 9     }   }  };  ​  const newObj = deepClone(obj)  newObj.info.hobby[2].a = 1234  console.log(newObj);

结果:

测试2  let test1 = {}  let test2 = {}  test2.test1 = test1  test1.test2 = test2  console.log(deepClone(test2));  ​  报错:  Uncaught RangeError: Maximum call stack size exceeded

原因:test1和test2分别作为属性值赋值给对方,在拷贝时,会发生重复拷贝,简而言之,就是缺少记录是否拷贝。

解决:使用 hashMap 哈希表方式记录键名是否存在,通过 WeakMap 实现。

封装函数2  function deepClone(origin, hashMap = new WeakMap()) {    if (origin === undefined || typeof origin !== 'object') { // 排除null、undefined、非object值      return origin;   }    if (origin instanceof Date) {      return new Date(origin);   }    if (origin instanceof RegExp) {      return new RegExp(origin);   }  ​    const hashKey = hashMap.get(origin); // 寻找键是否存在    if (hashKey) {      return hashKey   }  ​    // [] -> [], {} -> {}, 不需要判断是对象还是数组    const target = new origin.constructor()    hashMap.set(origin, target)    for (let k in origin) {      if (origin.hasOwnProperty(k)) {        target[k] = deepClone(origin[k], hashMap)     }   }  ​    return target;  } 测试3  let test1 = {}  let test2 = {}  test2.test1 = test1  test1.test2 = test2  console.log(deepClone(test2));

结果:

同系列文章请查看:【Github】pre-interview



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3