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 相关文章推荐
获取dom元素那些讨厌的位置封装代码
Jun 23 Javascript
一起来写段JS drag拖动代码
Dec 09 Javascript
javascript实现的弹出层背景置灰-模拟(easyui dialog)
Dec 27 Javascript
jquery缓动swing liner控制动画过程不同时刻的速度
May 29 Javascript
jquery插件uploadify实现带进度条的文件批量上传
Dec 13 Javascript
Javascript中常用的检测方法小结
Oct 08 Javascript
简单模拟node.js中require的加载机制
Oct 27 Javascript
微信小程序商城项目之侧栏分类效果(1)
Apr 17 Javascript
slideToggle+slideup实现手机端折叠菜单效果
May 25 Javascript
详解vue-cli 脚手架项目-package.json
Jul 04 Javascript
js实现验证码干扰(动态)
Feb 23 Javascript
Vue OpenLayer测距功能的实现
Apr 20 Vue.js
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实现多级树型菜单
2006/10/09 PHP
php+mysqli实现批量替换数据库表前缀的方法
2014/12/29 PHP
ThinkPHP框架实现的邮箱激活功能示例
2018/06/15 PHP
PHP pthreads v3下worker和pool的使用方法示例
2020/02/21 PHP
jQuery 操作XML入门
2008/12/25 Javascript
获取表单控件原始(初始)值的方法
2013/08/21 Javascript
判断文件是否正在被使用的JS代码
2013/12/21 Javascript
Node.js和PHP根据ip获取地理位置的方法
2014/03/14 Javascript
详解Bootstrap glyphicons字体图标
2016/01/04 Javascript
使用bootstrap typeahead插件实现输入框自动补全之问题及解决办法
2016/07/07 Javascript
js 去掉字符串前后空格实现代码集合
2017/03/25 Javascript
Bootstrap table学习笔记(2) 前后端分页模糊查询
2017/05/18 Javascript
webpack教程之webpack.config.js配置文件
2017/07/05 Javascript
bootstrap confirmation按钮提示组件使用详解
2017/08/22 Javascript
利用pm2部署多个node.js项目的配置教程
2017/10/22 Javascript
layui点击弹框页面 表单请求的方法
2019/09/21 Javascript
原生JS实现音乐播放器的示例代码
2021/02/25 Javascript
[02:22]《新闻直播间》2017年08月14日
2017/08/15 DOTA
python使用mysqldb连接数据库操作方法示例详解
2013/12/03 Python
python实现备份目录的方法
2015/08/03 Python
Phantomjs抓取渲染JS后的网页(Python代码)
2016/05/13 Python
深入解析Python中的线程同步方法
2016/06/14 Python
请不要重复犯我在学习Python和Linux系统上的错误
2016/12/12 Python
Python内置模块hashlib、hmac与uuid用法分析
2018/02/12 Python
对python 匹配字符串开头和结尾的方法详解
2018/10/27 Python
Django中使用Whoosh进行全文检索的方法
2019/03/31 Python
python切片(获取一个子列表(数组))详解
2019/08/09 Python
解决python执行较大excel文件openpyxl慢问题
2020/05/15 Python
Django ModelForm组件原理及用法详解
2020/10/12 Python
英国最大的在线照明商店:Litecraft
2020/08/31 全球购物
一年级家长会邀请函
2014/01/25 职场文书
经济管理毕业生求职信
2014/03/15 职场文书
课例研修方案
2014/05/31 职场文书
计算机相关专业自荐信
2014/07/02 职场文书
终止劳动合同通知书
2015/04/16 职场文书
2015年服务员个人工作总结
2015/05/27 职场文书