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-Easyui 1.2 实现多层菜单效果的代码
Jan 13 Javascript
多种方法判断Javascript对象是否存在
Sep 22 Javascript
JavaScript的原型继承详解
Feb 15 Javascript
jquery中radio checked问题
Mar 16 Javascript
javascript实现图片轮播效果
Jan 20 Javascript
轻松掌握jQuery中wrap()与unwrap()函数的用法
May 24 Javascript
js鼠标单击和双击事件冲突问题的快速解决方法
Jul 11 Javascript
详解Angular4中路由Router类的跳转navigate
Jun 09 Javascript
React-Native实现ListView组件之上拉刷新实例(iOS和Android通用)
Jul 11 Javascript
jQuery ajax仿Google自动提示SearchSuggess功能示例
Mar 28 jQuery
vue动态禁用控件绑定disable的例子
Oct 28 Javascript
VUE Elemen-ui之穿梭框使用方法详解
Jan 19 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 Mysql日期和时间函数集合
2007/11/16 PHP
Discuz 模板引擎的封装类代码
2008/07/18 PHP
PHP Curl多线程原理实例详解
2013/11/06 PHP
php中switch语句用法详解
2015/08/17 PHP
Zend Framework前端控制器用法示例
2016/12/11 PHP
JQUBAR1.1 jQuery 柱状图插件发布
2010/11/28 Javascript
自定义ExtJS控件之下拉树和下拉表格附源码
2013/10/15 Javascript
javascript实现存储hmtl字符串示例
2014/04/25 Javascript
javascript的alert box在java中如何显示多行
2014/05/18 Javascript
JS数字抽奖游戏实现方法
2015/05/04 Javascript
jQuery检查事件是否触发的方法
2015/06/26 Javascript
js如何准确获取当前页面url网址信息
2020/09/13 Javascript
如何利用JSHint减少JavaScript的错误
2016/08/23 Javascript
基于JavaScript实现屏幕滚动效果
2017/01/18 Javascript
Vue中的vue-resource示例详解
2018/11/02 Javascript
bootstrap 日期控件 datepicker被弹出框dialog覆盖的解决办法
2019/07/09 Javascript
微信小程序 select 下拉框组件功能
2019/09/09 Javascript
python下如何让web元素的生成更简单的分析
2008/07/17 Python
Python ORM框架SQLAlchemy学习笔记之数据添加和事务回滚介绍
2014/06/10 Python
Python中的作用域规则详解
2015/01/30 Python
Python操作csv文件实例详解
2017/07/31 Python
PyTorch中常用的激活函数的方法示例
2019/08/20 Python
Python (Win)readline和tab补全的安装方法
2019/08/27 Python
python GUI库图形界面开发之PyQt5控件数据拖曳Drag与Drop详细使用方法与实例
2020/02/27 Python
Matlab中plot基本用法的具体使用
2020/07/17 Python
Python容器类型公共方法总结
2020/08/19 Python
俄罗斯品牌服装和鞋子在线商店:BRIONITY
2020/03/26 全球购物
趣味活动策划方案
2014/02/08 职场文书
校庆标语集锦
2014/06/25 职场文书
2015年五一劳动节慰问信
2015/03/23 职场文书
2015年计生协会工作总结
2015/04/24 职场文书
上学路上观后感
2015/06/16 职场文书
Redis实现订单自动过期功能的示例代码
2021/05/08 Redis
Python制作一个随机抽奖小工具的实现
2021/07/07 Python
python机器学习实现oneR算法(以鸢尾data为例)
2022/03/03 Python
mysql数据库如何转移到oracle
2022/12/24 MySQL