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 相关文章推荐
Jquery+WebService 校验账号是否已被注册的代码
Jul 12 Javascript
Javascript中获取出错代码所在文件及行数的代码
Sep 23 Javascript
最短的IE判断代码
Mar 13 Javascript
javascript中的绑定与解绑函数应用示例
Jun 24 Javascript
js导出table数据到excel即导出为EXCEL文档的方法
Oct 10 Javascript
httpclient模拟登陆具体实现(使用js设置cookie)
Dec 11 Javascript
jQuery实现输入框邮箱内容自动补全与上下翻动显示效果【附demo源码下载】
Sep 20 Javascript
将input框中输入内容显示在相应的div中【三种方法可选】
May 08 Javascript
JavaScript实现设置默认日期范围为最近40天的方法分析
Jul 12 Javascript
webpack 开发和生产并行设置的方法
Nov 08 Javascript
bootstrap Table实现合并相同行
Jul 19 Javascript
JS精确判断数据类型代码实例
Dec 18 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
雄兵连三大错觉:凯莎没了,凉冰阵亡了,华烨觉得自己又行了
2020/04/09 国漫
php 获取今日、昨日、上周、本月的起始时间戳和结束时间戳的方法
2013/09/28 PHP
php递归获取目录内文件(包含子目录)封装类分享
2013/12/25 PHP
PHP Reflection API详解
2015/05/12 PHP
PHP将数据导出Excel表中的实例(投机型)
2017/07/31 PHP
图片按比例缩放函数
2006/06/26 Javascript
wordpress之js库集合研究介绍
2007/08/17 Javascript
jquery选择器-根据多个属性选择示例代码
2013/10/21 Javascript
判断日期是否能跨月查询的js代码
2014/07/25 Javascript
Linux CentOS系统下安装node.js与express的方法
2017/04/01 Javascript
Bootstrap实现基于carousel.js框架的轮播图效果
2017/05/02 Javascript
基于vue中对鼠标划过事件的处理方式详解
2018/08/22 Javascript
vue+elementui实现点击table中的单元格触发事件--弹框
2020/07/18 Javascript
ES6字符串的扩展实例
2020/12/21 Javascript
python中django框架通过正则搜索页面上email地址的方法
2015/03/21 Python
python实现复制整个目录的方法
2015/05/12 Python
Python的Django框架中forms表单类的使用方法详解
2016/06/21 Python
利用Python实现原创工具的Logo与Help
2018/12/03 Python
在 Python 中使用 MQTT的方法
2020/08/18 Python
深入剖析HTML5 内联框架iFrame
2016/05/04 HTML / CSS
德国在线订购鲜花:Fleurop
2018/08/25 全球购物
TCP/IP中的TCP和IP分别承担什么责任
2012/04/21 面试题
网络技术支持面试题
2013/04/22 面试题
求职者应聘的自我评价
2013/10/16 职场文书
后进生转化工作制度
2014/01/17 职场文书
在校实习生求职信
2014/06/18 职场文书
2014年图书管理员工作总结
2014/12/01 职场文书
公司财务经理岗位职责
2015/04/08 职场文书
员工福利申请报告
2015/05/15 职场文书
2016年社区创先争优活动总结
2016/04/05 职场文书
餐厅营销的秘密:为什么老顾客会流水?
2019/08/08 职场文书
MongoDB数据库常用的10条操作命令
2021/06/18 MongoDB
Python+Selenium自动化环境搭建与操作基础详解
2022/03/13 Python
集英社今正式宣布 成立游戏公司“集英社Games”
2022/03/31 其他游戏
Python进程池与进程锁之语法学习
2022/04/11 Python
如何通过cmd 连接阿里云服务器
2022/04/18 Servers