首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Javascript中如何实现对象的深拷贝 (前端高频面试题)

Javascript中如何实现对象的深拷贝 (前端高频面试题)

作者头像
henu_Newxc03
发布2022-05-05 17:17:04
发布2022-05-05 17:17:04
1.1K0
举报

最近参加百度前端训练营有节课讲到了JS对象的深拷贝,于是上网搜了一下相关文章,发现这是面试高频考题,于是乎写篇文章总结一下。

一. JS中为什么需要用到深拷贝?

要说到为什么需要深拷贝,就不得不提一嘴JS的对象引用传递了。

什么是对象引用传递?

代码语言:javascript
复制
var a = {name:'卡卡罗特'}
var b = a ;
a===b // true
b.name = '贝吉塔'
a.name //'贝吉塔'

在这里我们用=号把a的值赋给了b,但实际上a给b传的是a指向的地址罢了。

如果一个变量绑定到一个非基本数据类型(Array, Function, Object),那么它只记录了一个内存地址,该地址存放了具体的数据。注意之前提到指向基本数据类型的变量相当于包含了数据,而现在指向非基本数据类型的变量本身是不包含数据的

对于引用类型的变量,和=只会判断引用的地址是否相同,而不会判断对象具体里属性以及值是否相同。因此,如果两个变量指向相同的对象,则返回true。 什么是拷贝?

拷贝就是把父对象的的值遍历全都拷贝给子对象

代码语言:javascript
复制
var a = {name:'卡卡罗特'}
var b = Object.assign({}, a)
a===b // false
b.name = '贝吉塔'
a.name //'卡卡罗特'

上面代码将原始对象拷贝到一个空对象,就得到了原始对象的克隆,这时候a与b指向的是不同的栈对象,所以对b.name重新复制也不会影响到a.name。但是如果a.name是一个对象的引用,而不是一个字符串,那么上面的代码也会遇到一些问题,参考如下代码:

代码语言:javascript
复制
var a = {name:{firstName:'卡卡罗特',lastName:'孙悟空'}}
var b = Object.assign({}, a)
a===b // false
b.name.firstName = '贝吉塔'
a.name.firstName //'贝吉塔'

这时候我们发现改变b.name.firstName会影响到a.name.firstName 因为Object.assign()方法只是浅层拷贝,a.name是一个栈对象的引用,赋值给b时,b.name也同样是这个栈对象的引用

在很多情况下我们只是想获得一个独立的、与父对象所有属性值相同的的对象,所以我们需要深拷贝。

二.如何进行深拷贝?

1. 使用JSON.parse()与JSON.stringify()对对象进行拷贝

代码语言:javascript
复制
var clone = function (obj) {
    return JSON.parse(JSON.stringify(obj));
}

这种方法只适用于纯数据json对象,在其他一些情况下是有问题滴

代码语言:javascript
复制
var clone = function (obj) {
    return JSON.parse(JSON.stringify(obj));
}
var a = {a:function(){console.log('hello world')},b:{c:1},c:[1,2,3],d:"卡卡罗特",e:new Date(),f:null,g:undefined}
var b = clone(a)

不难发现该方法会忽略值为function以及undefied的字段,而且对date类型的支持也不太友好。更要紧的是,上述方法只能克隆原始对象自身的值,不能克隆它继承的值,参考如下代码:

代码语言:javascript
复制
function Person (name) {
    this.name = name
}
var Goku = new Person('卡卡罗特')
var newGoku = clone(Goku)
Goku.constructor === Person // true
newGoku.constructor === Object // true

2. 使用递归的方式实现深拷贝

代码语言:javascript
复制
function deepClone(source) {
  if (!source) return
  let target;
  if (typeof source === 'object') {
    // 根据source类型判断是新建一个数组还是对象
    target = Array.isArray(source) ? [] : {}
    // 遍历source,并且判断是source的属性才拷贝
    for (let key in source) {
      if (source.hasOwnProperty(key)) {
        if (typeof source[key] !== 'object') {
          target[key] = source[key]
        } else {
          // 如果内部属性存在复杂数据类型,使用递归实现深拷贝
          target[key] = deepClone(source[key])
        }
      }
    }
  } else {
    target = source
  }
  return target
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一. JS中为什么需要用到深拷贝?
  • 二.如何进行深拷贝?
    • 1. 使用JSON.parse()与JSON.stringify()对对象进行拷贝
    • 2. 使用递归的方式实现深拷贝
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档