前端开发您现在的位置是:首页 > 博客日志 > 前端开发

js 实现对象的拷贝、深拷贝

<a href='mailto:'>微wx笑</a>的头像微wx笑2021-01-13 08:41:15前端开发人已围观关键字: js  对象  拷贝  深拷贝  复制  vue  

在使用vue等响应式框架的时候,为了让框架能够监测到数据的改变,我们经常会用到对象的拷贝功能。这里收集了一些实现的方法及注意事项。Object.assign() 基本用法Object.assign

在使用vue等响应式框架的时候,为了让框架能够监测到数据的改变,我们经常会用到对象的拷贝功能。这里收集了一些实现的方法及注意事项。dEp编程技术_踩坑日志_进阶指南_无知人生


dEp编程技术_踩坑日志_进阶指南_无知人生

Object.assign() 

基本用法

Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。dEp编程技术_踩坑日志_进阶指南_无知人生

const target = { a: 1 };

const source1 = { b: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

注意点

(1)浅拷贝

Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。dEp编程技术_踩坑日志_进阶指南_无知人生

const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);

obj1.a.b = 2;
obj2.a.b // 2

上面代码中,源对象obj1的a属性的值是一个对象,Object.assign拷贝得到的是这个对象的引用。这个对象的任何变化,都会反映到目标对象上面。dEp编程技术_踩坑日志_进阶指南_无知人生

dEp编程技术_踩坑日志_进阶指南_无知人生

方法一:利用JSON.stringify和JSON.parse

let swr = {
    name:"邵威儒",
    age:28,
    pets:['小黄']
}

let swrcopy = JSON.parse(JSON.stringify(swr))
console.log(swrcopy) // { name: '邵威儒', age: 28, pets: [ '小黄' ] }
// 此时我们新增swr的属性
swr.pets.push('旺财')
console.log(swr) // { name: '邵威儒', age: 28, pets: [ '小黄', '旺财' ] }
// 但是swrcopy却不会受swr影响
console.log(swrcopy) // { name: '邵威儒', age: 28, pets: [ '小黄' ] }

这种方式进行深拷贝,只针对json数据这样的键值对有效dEp编程技术_踩坑日志_进阶指南_无知人生

对于函数等等反而无效,不好用,接着继续看方法二、三。dEp编程技术_踩坑日志_进阶指南_无知人生

方法二

function deepCopy(fromObj,toObj) { // 深拷贝函数
  // 容错
  if(fromObj === null) return null // 当fromObj为null
  if(fromObj instanceof RegExp) return new RegExp(fromObj) // 当fromObj为正则
  if(fromObj instanceof Date) return new Date(fromObj) // 当fromObj为Date

  toObj = toObj || {}
  
  for(let key in fromObj){ // 遍历
    if(typeof fromObj[key] !== 'object'){ // 是否为对象
      toObj[key] = fromObj[key] // 如果为普通值,则直接赋值
    }else{
      if(fromObj[key] === null){
        toObj[key] = null
      }else{
        toObj[key] = new fromObj[key].constructor // 如果为object,则new这个object指向的构造函数
        deepCopy(fromObj[key],toObj[key]) // 递归          
      }
    }
  }
  return toObj
}

let dog = {
  name:"小白",
  sex:"公",
  firends:[
    {
      name:"小黄",
      sex:"母"
    }
  ]
}

let dogcopy = deepCopy(dog)
// 此时我们把dog的属性进行增加
dog.firends.push({name:"小红",sex:"母"})
console.log(dog) // { name: '小白',
                      sex: '公',
                      firends: [ { name: '小黄', sex: '母' }, { name: '小红', sex: '母' } ] }
// 当我们打印dogcopy,会发现dogcopy不会受dog的影响
console.log(dogcopy) // { name: '小白',
                          sex: '公',
                          firends: [ { name: '小黄', sex: '母' } ] }

方法三

let dog = {
  name:"小白",
  sex:"公",
  firends:[
    {
      name:"小黄",
      sex:"母"
    }
  ]
}

function deepCopy(obj) {
  if(obj === null) return null
  if(typeof obj !== 'object') return obj
  if(obj instanceof RegExp) return new RegExp(obj)
  if(obj instanceof Date) return new Date(obj)
  let newObj = new obj.constructor
  for(let key in obj){
    newObj[key] = deepCopy(obj[key])
  }
  return newObj
}

let dogcopy = deepCopy(dog)
dog.firends.push({name:"小红",sex:"母"})
console.log(dogcopy)

方法四

function deepClone(data){
       var type = getType(data);
       var obj;
       if(type === 'array'){
           obj = [];
       } else if(type === 'object'){
           obj = {};
       } else {
           //不再具有下一层次
           return data;
       }
       if(type === 'array'){
           for(var i = 0, len = data.length; i < len; i++){
               obj.push(deepClone(data[i]));
           }
       } else if(type === 'object'){
           for(var key in data){
               obj[key] = deepClone(data[key]);
           }
       }
       return obj;
   }


dEp编程技术_踩坑日志_进阶指南_无知人生


dEp编程技术_踩坑日志_进阶指南_无知人生

相关参考:
【ES6学习笔记之】Object.assign()dEp编程技术_踩坑日志_进阶指南_无知人生

ES6——解构赋值dEp编程技术_踩坑日志_进阶指南_无知人生

vue中 实现对象的深拷贝dEp编程技术_踩坑日志_进阶指南_无知人生

本文由 微wx笑 创作,采用 CC BY-NC 4.0 许可协议。 非商业性使用可自由转载、引用、甚至修改,但需署名作者且注明出处。

很赞哦! () 有话说 ()