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表数据排序 sort table data
Feb 18 Javascript
JQuery中关于jquery.js与jquery.min.js的比较探讨
May 15 Javascript
Js 正则表达式知识汇总
Dec 02 Javascript
jQuery中die()方法用法实例
Jan 19 Javascript
JavaScript驾驭网页-获取网页元素
Mar 24 Javascript
无需 Flash 使用 jQuery 复制文字到剪贴板
Apr 26 Javascript
Bootstrap3 Grid system原理及应用详解
Sep 30 Javascript
Vue.js开发环境搭建
Nov 10 Javascript
jfinal与bootstrap的登出实战详解
Nov 27 Javascript
详解如何使用 vue-cli 开发多页应用
Dec 16 Javascript
jQuery - AJAX load() 实例用法详解
Aug 27 jQuery
webpack 动态批量加载文件的实现方法
Mar 19 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读MYSQL中文乱码的解决方法
2006/12/17 PHP
php获取数组中重复数据的两种方法
2013/06/28 PHP
PHP实现二维数组按某列进行排序的方法
2016/11/18 PHP
js或css实现滚动广告的几种方案
2010/01/28 Javascript
jquery 日期分离成年月日的代码
2010/05/14 Javascript
String.prototype实现的一些javascript函数介绍
2013/11/22 Javascript
Node.js 去掉种子(torrent)文件里的邪恶信息
2015/03/27 Javascript
JavaScript判断按钮被点击的方法
2015/12/13 Javascript
把多个JavaScript函数绑定到onload事件处理函数上的方法
2016/09/04 Javascript
详解XMLHttpRequest(二)响应属性、二进制数据、监测上传下载进度
2016/09/14 Javascript
JS闭包与延迟求值用法示例
2016/12/22 Javascript
Bootstrap Table使用整理(五)之分页组合查询
2017/06/09 Javascript
微信小程序loading组件显示载入动画用法示例【附源码下载】
2017/12/09 Javascript
基于node搭建服务器,写接口,调接口,跨域的实例
2018/05/13 Javascript
vue动态绑定class选中当前列表变色的方法示例
2018/12/19 Javascript
Nodejs处理异常操作示例
2018/12/25 NodeJs
Vue中key的作用示例代码详解
2020/06/10 Javascript
vue 实现setInterval 创建和销毁实例
2020/07/21 Javascript
将tensorflow模型打包成PB文件及PB文件读取方式
2020/01/23 Python
html5图片上传预览示例分享
2014/04/14 HTML / CSS
应届生英语教师求职信
2013/11/05 职场文书
应届医学毕业生求职信分享
2013/12/02 职场文书
和平主题的演讲稿
2014/01/12 职场文书
工程采购员岗位职责
2014/03/09 职场文书
先进事迹报告会主持词
2014/04/02 职场文书
法人委托书范本格式
2014/09/15 职场文书
乡镇干部个人对照检查材料思想汇报(原创篇)
2014/09/28 职场文书
具结保证书
2015/01/17 职场文书
升职感谢信
2015/01/22 职场文书
白鹤梁导游词
2015/02/06 职场文书
行政二审代理词
2015/05/25 职场文书
JavaScript嵌入百度地图API的最详细方法
2021/04/16 Javascript
Golang 使用Map实现去重与set的功能操作
2021/04/29 Golang
php png失真的原因及解决办法
2021/10/24 PHP
Java实现添加条码或二维码到Word文档
2022/06/01 Java/Android
使用JS前端技术实现静态图片局部流动效果
2022/08/05 Javascript