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 闭包
Sep 15 Javascript
Jquery UI震动效果实现原理及步骤
Feb 04 Javascript
jquery实现加载等待效果示例
Sep 25 Javascript
javascript 实现子父窗体互相传值的简单实例
Feb 17 Javascript
基于jquery实现发送文章到手机的代码
Dec 26 Javascript
javascript实现在下拉列表中显示多级树形菜单的方法
Aug 12 Javascript
总结在前端排序中遇到的问题
Jul 19 Javascript
JavaScript编写九九乘法表(两种任选)
Feb 04 Javascript
react在安卓中输入框被手机键盘遮挡问题的解决方法
Sep 03 Javascript
基于vue-cli npm run build之后vendor.js文件过大的解决方法
Sep 27 Javascript
浅谈微信小程序列表埋点曝光指南
Oct 15 Javascript
如何实现echarts markline标签名显示自己想要的
Jul 20 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
请离开include_once和require_once
2013/07/18 PHP
64位windows系统下安装Memcache缓存
2015/12/06 PHP
Thinkphp开发--集成极光推送
2017/09/15 PHP
PHP中使用jQuery+Ajax实现分页查询多功能操作(示例讲解)
2017/09/17 PHP
PHP curl批处理及多请求并发实现方法分析
2018/08/15 PHP
PHP中通过getopt解析GNU C风格命令行选项
2019/11/18 PHP
动态为事件添加js代码示例
2009/02/15 Javascript
jQuery动态添加、删除元素的方法
2014/01/09 Javascript
js插件设置innerHTML时在IE8下提示“未知运行时错误”解决方法
2015/04/25 Javascript
javascript实现动态导入js与css等静态资源文件的方法
2015/07/25 Javascript
JavaScript SHA512&SHA256加密算法详解
2015/08/11 Javascript
3种不同的ContextMenu右键菜单实现代码
2016/11/03 Javascript
JavaScript实现打地鼠小游戏
2020/04/23 Javascript
vue如何安装使用Quill富文本编辑器
2018/09/21 Javascript
OpenLayer学习之自定义测量控件
2020/09/28 Javascript
vue常用高阶函数及综合实例
2021/02/25 Vue.js
python通过pil为png图片填充上背景颜色的方法
2015/03/17 Python
在Docker上部署Python的Flask框架的教程
2015/04/08 Python
Django 前后台的数据传递的方法
2017/08/08 Python
Python基于TCP实现会聊天的小机器人功能示例
2018/04/09 Python
Python3.x爬虫下载网页图片的实例讲解
2018/05/22 Python
用纯CSS3实现网页中常见的小箭头
2017/10/16 HTML / CSS
HTML 5.1来了 9月份正式发布 更新内容预览
2016/04/26 HTML / CSS
英国儿童设计师服装的领先零售商:Base
2019/03/17 全球购物
在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern "C"
2014/08/09 面试题
酒店人事专员岗位职责
2013/12/19 职场文书
党员自我批评与反省材料
2014/02/10 职场文书
学习决心书
2014/03/11 职场文书
十佳好少年事迹材料
2014/08/21 职场文书
2015教师年度工作总结范文
2015/04/07 职场文书
2016春节放假通知范文
2015/08/18 职场文书
《活见鬼》教学反思
2016/02/24 职场文书
创业不要错过,这4种餐饮新模式
2019/07/18 职场文书
2019职场单身人才调研报告:互联网行业单身比例最高
2019/08/07 职场文书
pytorch 两个GPU同时训练的解决方案
2021/06/01 Python
Oracle以逗号分隔的字符串拆分为多行数据实例详解
2021/07/16 Oracle