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表单验证代码(包括例子)
Nov 11 Javascript
multiSteps 基于Jquery的多步骤滑动切换插件
Jul 22 Javascript
关于include标签导致js路径找不到的问题分析及解决
Jul 09 Javascript
js实现编辑div节点名称的方法
Dec 17 Javascript
jQuery实现宽屏图片轮播实例教程
Nov 24 Javascript
详解JavaScript节流函数中的Throttle
Jul 16 Javascript
基于JSON格式数据的简单jQuery幻灯片插件(jquery-slider)
Aug 10 Javascript
jQuery鼠标移动图片上实现放大效果
Jun 25 jQuery
深入浅析javascript函数中with
Oct 28 Javascript
小程序如何使用分包加载的实现方法
May 22 Javascript
微信小程序常用的3种提示弹窗实现详解
Sep 19 Javascript
vue+AI智能机器人回复功能实现
Jul 16 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实现密保卡功能实现代码<打包下载直接运行>
2011/10/09 PHP
php提示Call-time pass-by-reference has been deprecated in的解决方法[已测]
2012/05/06 PHP
php判断数组元素中是否存在某个字符串的方法
2014/06/14 PHP
laravel使用Faker数据填充的实现方法
2019/04/12 PHP
JS关键字变色实现思路及代码
2013/02/21 Javascript
页面元素绑定jquery toggle后元素隐藏的解决方法
2014/03/27 Javascript
js判断一个字符串是否包含一个子串的方法
2015/01/26 Javascript
javascript实现链接单选效果的方法
2015/05/13 Javascript
基于jquery实现人物头像跟随鼠标转动
2015/08/23 Javascript
javascript日期格式化方法小结
2015/12/17 Javascript
js控制文本框只能输入中文、英文、数字与指定特殊符号的实现代码
2016/09/09 Javascript
使用JS中的Replace()方法遇到的问题小结
2017/10/20 Javascript
JavaScript实现拖拽效果
2020/03/16 Javascript
JavaScript实时更新当前的时间的示例代码
2020/07/15 Javascript
解决Echarts 显示隐藏后宽度高度变小的问题
2020/07/19 Javascript
多个Vue项目部署到服务器的步骤记录
2020/10/22 Javascript
[32:17]完美世界DOTA2联赛循环赛LBZS vs Forest第二场 10月30日
2020/10/31 DOTA
Python 安装setuptools和pip工具操作方法(必看)
2017/05/22 Python
Python3 处理JSON的实例详解
2017/10/29 Python
python获取url的返回信息方法
2018/12/17 Python
Python实现字符型图片验证码识别完整过程详解
2019/05/10 Python
python与mysql数据库交互的实现
2020/01/06 Python
Python计算指定日期是今年的第几天(三种方法)
2020/03/26 Python
Jupyter Notebook输出矢量图实例
2020/04/14 Python
IE10 Error.stack 让脚本调试更加方便快捷
2013/04/22 HTML / CSS
猎人靴英国官网:Hunter Boots
2017/02/02 全球购物
EJB发布WEB服务一般步骤
2012/10/31 面试题
初一体育教学反思
2014/01/29 职场文书
学校搬迁方案
2014/06/15 职场文书
父亲婚礼答谢词
2015/01/04 职场文书
2015年教师节演讲稿范文
2015/03/19 职场文书
2015年科普工作总结
2015/07/23 职场文书
入伍志愿书怎么写?
2019/07/19 职场文书
教你利用Selenium+python自动化来解决pip使用异常
2021/05/20 Python
HTML基础详解(上)
2021/10/16 HTML / CSS
ipad隐藏软件app图标方法
2022/04/19 数码科技