JS面试题中深拷贝的实现讲解

 更新时间:2020年05月07日 08:22:37   作者:沐晓  
在本篇文章里小编给大家分享的是关于JS面试题中深拷贝的实现讲解,需要的朋友们可以参考下。

在面试中你是否遇到过如下场景:

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 获取图片颜色

    html 5.0的canvas可以获取到图片的像素点了。这样,我们可以做很多以图片有关的操作和渲染了。当然今后也会给浏览器渲染引擎更高的要求。(YY, 什么时候html渲染引擎也支持多核和GPU呢?)
    2009-04-04
  • JavaScript实现拼音排序的方法

    JavaScript实现拼音排序的方法

    本文将介绍JavaScript如何实现拼音排序 支持所有主流浏览器+中英文系统
    2012-11-11
  • 在js文件中引入(调用)另一个js文件的三种方法

    在js文件中引入(调用)另一个js文件的三种方法

    这篇文章主要介绍了在js文件中引入(调用)另一个js文件的三种方法,帮助大家更好的理解和学习JavaScript,感兴趣的朋友可以了解下
    2020-09-09
  • JavaScript中的闭包

    JavaScript中的闭包

    闭包,官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分
    2016-02-02
  • 用JS实现飞机大战小游戏

    用JS实现飞机大战小游戏

    这篇文章主要为大家详细介绍了用JS实现飞机大战小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • 24行JavaScript代码实现Redux的方法实例

    24行JavaScript代码实现Redux的方法实例

    这篇文章主要给大家介绍了关于如何利用24行JavaScript代码实现Redux的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用JavaScript具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-11-11
  • 两种简单的跨域方法(jsonp、php)

    两种简单的跨域方法(jsonp、php)

    这篇文章主要为大家详细介绍了两种简单的跨域方法,使用jsonp和php实现跨域,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01
  • 用js屏蔽被http劫持的浮动广告实现方法

    用js屏蔽被http劫持的浮动广告实现方法

    下面小编就为大家带来一篇用js屏蔽被http劫持的浮动广告实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • js学习总结之DOM2兼容处理this问题的解决方法

    js学习总结之DOM2兼容处理this问题的解决方法

    这篇文章主要为大家详细介绍了js学习总结之DOM2兼容处理this问题的解决方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • js通过循环多张图片实现动画效果

    js通过循环多张图片实现动画效果

    这篇文章主要为大家详细介绍了js通过循环多张图片实现动画效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-12-12

最新评论