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 相关文章推荐
一些经常会用到的Javascript检测函数
May 31 Javascript
dojo随手记 gird组件引用
Feb 24 Javascript
在jquery boxy中添加百度地图坐标拾取注意流程
Apr 03 Javascript
推荐JavaScript实现继承的最佳方式
Nov 11 Javascript
WebApi+Bootstrap+KnockoutJs打造单页面程序
May 16 Javascript
详解bootstrap的modal-remote两种加载方式【强化】
Jan 27 Javascript
node操作mysql数据库实例详解
Mar 17 Javascript
validationEngine 表单验证插件使用实例代码
Jun 15 Javascript
AngularJS动态添加数据并删除的实例
Feb 27 Javascript
QQ跳转支付宝并自动领红包脚本(最新)
Jun 22 Javascript
Angular Excel 导入与导出的实现代码
Apr 17 Javascript
微信小程序云开发 生成带参小程序码流程
May 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
javascript call方法使用说明
2010/01/11 Javascript
jQuery 操作option的实现代码
2011/03/03 Javascript
50款非常棒的 jQuery 插件分享
2012/03/29 Javascript
用js控件div的滚动条,让它在内容更新时自动滚到底部的实现方法
2016/10/27 Javascript
jquery操作ID带有变量的节点实例
2016/12/07 Javascript
sublime text配置node.js调试(图文教程)
2017/11/23 Javascript
vue组件编写之todolist组件实例详解
2018/01/22 Javascript
vue.extend实现alert模态框弹窗组件
2018/04/28 Javascript
jQuery插件Validation表单验证详解
2018/05/26 jQuery
vue路由前进后退动画效果的实现代码
2018/12/10 Javascript
玩转Koa之koa-router原理解析
2018/12/29 Javascript
详解webpack引入第三方库的方式以及注意事项
2019/01/15 Javascript
浅谈Three.js截图并下载的大坑
2019/11/01 Javascript
Vue时间轴 vue-light-timeline的用法说明
2020/10/29 Javascript
使用PyInstaller将Python程序文件转换为可执行程序文件
2016/07/08 Python
pytorch 把MNIST数据集转换成图片和txt的方法
2018/05/20 Python
Django 路由控制的实现代码
2018/11/08 Python
使用 Visual Studio Code(VSCode)搭建简单的Python+Django开发环境的方法步骤
2018/12/17 Python
python itchat给指定联系人发消息的方法
2019/06/11 Python
PyCharm 2019.3发布增加了新功能一览
2019/12/08 Python
python实现用类读取文件数据并计算矩形面积
2020/01/18 Python
python时间日期操作方法实例小结
2020/02/06 Python
Spring Boot中使用IntelliJ IDEA插件EasyCode一键生成代码详细方法
2020/03/20 Python
基于K.image_data_format() == 'channels_first' 的理解
2020/06/29 Python
Django中Aggregation聚合的基本使用方法
2020/07/09 Python
Python json解析库jsonpath原理及使用示例
2020/11/25 Python
使用Python通过oBIX协议访问Niagara数据的示例
2020/12/04 Python
全球最大化妆品零售网站:SkinStore
2020/10/24 全球购物
全球精选男装和家居用品:Article
2020/04/13 全球购物
园长自我鉴定
2013/10/06 职场文书
食品营养与检测应届生求职信
2013/11/08 职场文书
幼儿园教师请假制度
2014/01/16 职场文书
大学军训感言1000字
2014/02/25 职场文书
中秋晚会策划方案
2014/06/12 职场文书
爱岗敬业事迹材料
2014/12/24 职场文书
java中用float时,数字后面加f,这样是为什么你知道吗
2021/09/04 Java/Android