JS面试题中深拷贝的实现讲解


Posted in Javascript onMay 07, 2020

在面试中你是否遇到过如下场景:

Q:小朋友,你是否了解如何拷贝一个对象?

R:此时,机智的你可能会想到

Object.assign({}, obj);

Q:那如何深拷贝一个对象呢?

R:机智的你

JSON.parse(JSON.stringify(obj));

Q:使用stringify这种方式有何弊端?

  1. 性能问题,stringify再解析其实需要耗费较多时间,特别是数据量大的时候。
  2. 一些类型无法拷贝,例如函数(不输出),正则(输出空对象),时间对象(输出时间字符串),Undefiend(不输出)
  3. 遇到循环引用的对象会出错
  4. 同层(非同层)同引用的问题,理论下两个key对应的val如果指向同一个对象,拷贝也应该指向一个相同新地址才对

Q:那你能自己实现个深拷贝函数?

R:如下:

const deepClone = (obj) => {
 // 非引用类型及函数将直接返回
 if (!obj || typeof obj !== 'object') return obj;

 // 特殊的引用类型处理
 switch(Object.prototype.toString.call(obj).slice(8, -1)) {
  case 'Date': 
   return new Date(obj);
   break;
  case 'RegExp': 
   return new RegExp(obj);
   break;
  case 'String': 
   return new String(obj);
   break;
  case 'Number': 
   return new Number(obj);
   break;
  case 'Boolean': 
   return new Boolean(obj);
   break;
 }

 const result = obj instanceof Array ? [] : {};

 for (let propName in obj) {
  if (obj.hasOwnProperty(propName)) {
   result[propName] = deepClone(obj[propName]);
  }
 }

 return result;
}

优点:实现了大多数数据类型的拷贝,所有非引用类型及引用类型的String Number Boolean Function Array Date RegExp

缺点:未考虑一些特殊的引用类型如Error Math Symbol Map Set JSON,函数属于引用拷贝,未解决循环引用的问题

Q:如何解决循环引用?

R:将父层级的数据缓存对比(可以顺带解决同层(非同层)同引用的问题)

const deepClone = (obj) => {
 // 非引用类型及函数将直接返回
 if (!obj || typeof obj !== 'object') return obj;

 // 特殊的引用类型处理
 switch (Object.prototype.toString.call(obj).slice(8, -1)) {
  case 'Date':
   return new Date(obj);
   break;
  case 'RegExp':
   return new RegExp(obj);
   break;
  case 'String':
   return new String(obj);
   break;
  case 'Number':
   return new Number(obj);
   break;
  case 'Boolean':
   return new Boolean(obj);
   break;
 }

 const map = deepClone.map = deepClone.map || new Map();

 // 使用map结构可以不必循环缓存,提高效率
 if (map.get(obj)) {
  return map.get(obj);
 }

 const result = obj instanceof Array ? [] : {};

 // 如果仔细观察可以发现解决了同层同引用的问题
 map.set(obj, result);

 for (let propName in obj) {
  if (obj.hasOwnProperty(propName)) {
   result[propName] = deepClone(obj[propName]);
  }
 }

 return result;
}

Q:为什么函数还是指向原来的函数,而不创建新函数?

R:理论下函数也可以通过new Function(code)来创建新的函数,但是如果遇到闭包函数,我们无法得到原函数的外层定义的变量及其原有作用域链,这些在JS词法解析时完成的步骤我们无法得知,所有只能引用原函数比较好。

Sum: 上面实现的缺点主要是没有完全覆盖特殊引用类型,但其实我们平时应该不会遇到那些类型,所以可以凑合使用。如果还有其它的问题没有考虑到或者有出错的,希望大家可以帮忙指出。

以上就是JS面试题中深拷贝的实现讲解的详细内容,更多关于JS深拷贝的实现的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
效率高的Javscript字符串替换函数的benchmark
Aug 02 Javascript
EXT中xtype的含义分析
Jan 07 Javascript
js实现精确到秒的日期选择器完整实例
Apr 30 Javascript
vue之数据交互实例代码
Jun 20 Javascript
javascript Function函数理解与实战
Dec 01 Javascript
vue中vee validate表单校验的几种基本使用
Jun 25 Javascript
在小程序/mpvue中使用flyio发起网络请求的方法
Sep 13 Javascript
新版小程序登录授权的方法
Dec 12 Javascript
vue.js中ref和$refs的使用及示例讲解
Aug 14 Javascript
javascript的惯性运动实现代码实例
Sep 07 Javascript
Layui实现数据表格中鼠标悬浮图片放大效果,离开时恢复原图的方法
Sep 11 Javascript
React生命周期原理与用法踩坑笔记
Apr 28 Javascript
javascript 代码是如何被压缩的示例代码
May 06 #Javascript
Layui弹框中数据表格中可双击选择一条数据的实现
May 06 #Javascript
Vue SSR 即时编译技术的实现
May 06 #Javascript
深入webpack打包原理及loader和plugin的实现
May 06 #Javascript
将Vue组件库更换为按需加载的方法步骤
May 06 #Javascript
让IDE识别webpack的别名alias的实现方法
May 06 #Javascript
JS 设计模式之:工厂模式定义与实现方法浅析
May 06 #Javascript
You might like
php中将数组转成字符串并保存到数据库中的函数代码
2013/09/29 PHP
简单的php+mysql聊天室实现方法(附源码)
2016/01/05 PHP
使用正则去除php代码中的注释方法
2016/11/03 PHP
动态创建样式表在各浏览器中的差异测试代码
2011/09/13 Javascript
jQuery+CSS 实现随滚动条增减的汽水瓶中的液体效果
2011/09/26 Javascript
jquery ajax请求方式与提示用户正在处理请稍等
2014/09/01 Javascript
jQuery使用hide方法隐藏元素自身用法实例
2015/03/30 Javascript
js自定义回调函数
2015/12/13 Javascript
基于jquery实现表格无刷新分页
2016/01/07 Javascript
温习Javascript基础语法之词法结构
2016/05/31 Javascript
JS与HTML结合使用marquee标签实现无缝滚动效果代码
2016/07/05 Javascript
jquery过滤特殊字符',防sql注入的实现方法
2016/08/17 Javascript
遍历js中对象的属性和值的实例
2016/11/21 Javascript
easyUI下拉列表点击事件使用方法
2017/05/18 Javascript
深入理解vue中的$set
2017/06/01 Javascript
AngularJs+Bootstrap实现漂亮的计算器
2017/08/10 Javascript
React-Router如何进行页面权限管理的方法
2017/12/06 Javascript
微信小程序判断页面是否从其他页面返回的实例代码
2019/07/03 Javascript
layui输入框中只允许输入整数的实现方法
2019/09/18 Javascript
Vue使用NProgress进度条的方法
2019/09/21 Javascript
15分钟学会vue项目改造成SSR(小白教程)
2019/12/17 Javascript
实用的 vue tags 创建缓存导航的过程实现
2020/12/03 Vue.js
Vue实现简单购物车功能
2020/12/13 Vue.js
python中lambda与def用法对比实例分析
2015/04/30 Python
浅谈python常用程序算法
2019/03/22 Python
python调用其他文件函数或类的示例
2019/07/16 Python
基于PyQT实现区分左键双击和单击
2020/05/19 Python
python实点云分割k-means(sklearn)详解
2020/05/28 Python
学生个人的自我评价分享
2013/11/05 职场文书
降消项目实施方案
2014/03/30 职场文书
工作评语大全
2014/04/26 职场文书
合作协议书范本
2014/10/25 职场文书
撤诉申请怎么写
2015/05/19 职场文书
员工安全责任协议书
2016/03/22 职场文书
使用Python获取字典键对应值的方法
2022/04/26 Python
Windows server 2012 R2 安装IIS服务器
2022/04/29 Servers