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 相关文章推荐
js split 的用法和定义 js split分割字符串成数组的实例代码
May 13 Javascript
使用JavaScript和C#中获得referer
Nov 14 Javascript
js实现的捐赠管理完整实例
Jan 20 Javascript
web前端开发upload上传头像js示例代码
Oct 22 Javascript
JS中substring与substr的用法
Nov 16 Javascript
JavaScript框架Angular和React深度对比
Nov 20 Javascript
redux中间件之redux-thunk的具体使用
Apr 17 Javascript
微信小程序收藏功能的实现代码
Jun 12 Javascript
小程序如何自主实现拦截器的示例代码
Nov 04 Javascript
vue proxy 的优势与使用场景实现
Jun 15 Javascript
浅谈vue中document.getElementById()拿到的是原值的问题
Jul 26 Javascript
ant-design-vue 时间选择器赋值默认时间的操作
Oct 27 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 mail 通过Windows的SMTP发送邮件失败的解决方案
2009/05/27 PHP
php递归函数中使用return的注意事项
2014/01/17 PHP
php 判断服务器操作系统的类型
2014/02/17 PHP
Yii2使用小技巧之通过 Composer 添加 FontAwesome 字体资源
2014/06/22 PHP
yii2控制器Controller Ajax操作示例
2016/07/23 PHP
js 目录列举函数
2008/11/06 Javascript
js 处理数组重复元素示例代码
2013/12/27 Javascript
自定义jquery模态窗口插件无法在顶层窗口显示问题
2014/05/29 Javascript
JS代码随机生成姓名、手机号、身份证号、银行卡号
2016/04/27 Javascript
微信小程序开发实战教程之手势解锁
2016/11/18 Javascript
js移动焦点到最后位置的简单方法
2016/11/25 Javascript
原生js实现鼠标跟随效果
2017/02/28 Javascript
axios全局请求参数设置,请求及返回拦截器的方法
2018/03/05 Javascript
详解ECMAScript typeof用法
2018/07/25 Javascript
VUE-Table上绑定Input通过render实现双向绑定数据的示例
2018/08/27 Javascript
element ui table 增加筛选的方法示例
2018/11/02 Javascript
详解Node.js amqplib 连接 Rabbit MQ最佳实践
2019/01/24 Javascript
实例解析Python的Twisted框架中Deferred对象的用法
2016/05/25 Python
用python找出那些被“标记”的照片
2017/04/20 Python
python合并已经存在的sheet数据到新sheet的方法
2018/12/11 Python
解决os.path.isdir() 判断文件夹却返回false的问题
2019/11/29 Python
Python中if有多个条件处理方法
2020/02/26 Python
Pandas对DataFrame单列/多列进行运算(map, apply, transform, agg)
2020/06/14 Python
Pycharm快捷键配置详细整理
2020/10/13 Python
美国领先的家居装饰和礼品商店:Kirkland’s
2017/01/30 全球购物
优秀团员个人的自我评价
2013/10/02 职场文书
专科毕业生求职简历的自我评价
2013/10/12 职场文书
保险专业大专生求职信
2013/10/26 职场文书
产品销售计划书
2014/05/04 职场文书
2014年党员干部四风问题自我剖析材料
2014/09/29 职场文书
医院党的群众路线教育实践活动学习心得体会
2014/10/30 职场文书
个人优缺点总结
2015/02/28 职场文书
上课讲话检讨书范文
2015/05/07 职场文书
vue中this.$http.post()跨域和请求参数丢失的解决
2022/04/08 Vue.js
Java中生成微信小程序太阳码的实现方案
2022/06/01 Java/Android
面试官问我Mysql的存储引擎了解多少
2022/08/05 MySQL