Skip to content

[js] 第71天 说说你对深浅拷贝的理解?并实现一个对数组和对象深拷贝的方法 #504

Open
@haizhilin2013

Description

@haizhilin2013

第71天 说说你对深浅拷贝的理解?并实现一个对数组和对象深拷贝的方法

Activity

haizhilin2013

haizhilin2013 commented on Jun 25, 2019

@haizhilin2013
CollaboratorAuthor

这道题跟第44天的题类似。多了说明深浅拷贝的理解,同时方法多了对数组的支持。
第44天的题:#167

AnsonZnl

AnsonZnl commented on Jun 26, 2019

@AnsonZnl
Contributor

为什么要进行拷贝

var obj1={
    value: 'a'
}
var obj2 = obj1;
obj2.value='b';
console.log(obj1);//{ value: 'b' }

因为对象是引用类型,所以赋值时的操作仅是赋予相同的地址,当对其中一个对象进行操作时,就会影响其他的对象。解决这个问题就需要拷贝了。

浅拷贝:

使用原生的Object.assign() 方法就可以实现浅拷贝

var obj1={
    value: 'a'
}
var obj2 = Object.assign({},obj1);
obj2.value='b';
console.log(obj1);//{ value: 'a' }

但是如果拷贝的源对象当中包含对象时,OBject.assign()方法只会拷贝对象的引用地址

var obj1={
    value: 'a',
    obj3:{
        value2: 'c'
    }
}
var obj2 = Object.assign({},obj1);
obj2.obj3.value2='b';
console.log(obj1);//{ value: 'a', obj3:{ value2: 'b' } }

深拷贝

如果要拷贝的对象中包含对象,就需要深拷贝了,一般使用原生的方法JSON.parse(JSON.stringify(obj))

j1={
    value: 'a',
    obj3:{
        value2: 'c'
    },
    arr:[1,2,3]
}
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.obj3.value2='b';
obj2.arr[0]= "a";
console.log(obj2);//{ value: 'a', obj3:{ value2: 'b' }, arr:['a',2,3] }
console.log(obj1);//{ value: 'a', obj3:{ value2: 'c' }, arr:[1,2,3] } 没有发生改变

实现一个对数组和对象的深拷贝的方法

var obj={
    name: 'znl',
    age: 18,
    friend:{
        name: 'borys',
        age: 20
    },
    arr:[1,2,[3,4]]
}

function copy(obj){
    var type=Object.prototype.toString.call(obj);
    if(!(type == '[object Array]' || type == '[object Object]')){
        return 'Type Error!';
    }
    return JSON.parse(JSON.stringify(obj));
}

var obj2= copy(obj);
console.log(obj.friend === obj2.friend)//false
console.log(obj.arr === obj2.arr)//false

参考:

MY729

MY729 commented on Jul 2, 2019

@MY729

浅拷贝 vs 深拷贝

补充一个用到的数组浅拷贝的方法 Array.from()

Kntt

Kntt commented on Jul 5, 2019

@Kntt
function clone (obj) {
  let buf
  if (obj instanceof Array || (obj instanceof Object && typeof obj !== 'function')) {
    buf = obj instanceof Array ? [] : {}
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
          buf[key] = clone(obj[key])
      }
    }
  } else {
    return obj
  }
  return buf
}
chenyouf1996

chenyouf1996 commented on Jul 29, 2019

@chenyouf1996
function deepClone (obj) {
  //判断克隆对象为数组还是对象 
  var newObj = obj.constructor === Array ? [] : {};
  for (var item in obj) {
    //若数组元素或对象属性为'object'则递归调用自身深度克隆对象或数组
    if (typeof obj[item] === 'object') {
      newObj[item] = deepClone(obj[item]);
    }
    //基本数据类型直接赋值
    else {
      newObj[item] = obj[item];
    }
  }
  return newObj;
}
rni-l

rni-l commented on Jan 20, 2020

@rni-l
function deepClone(val) {
  function getType(_val) {
    return Object.prototype.toString.call(_val).replace(/[\[\s\]]|(object)/g, '')
  }
  const valType = getType(val);
  if (valType !== 'Object' && valType !== 'Array') return val
  let output = {}
  if (valType === 'Array') {
    output = []
    val.forEach(v => {
      const curValType = getType(v)
      if (curValType === 'Array' || curValType === 'Object') {
        output.push(deepClone(v))
      } else {
        output.push(v)
      }
    })
  } else if (valType === 'Object') {
    Object.keys(val).forEach(v => {
      const curValType = getType(v)
      if (curValType === 'Array' || curValType === 'Object') {
        output[v]= (deepClone(val[v]))
      } else {
        output[v]= (val[v])
      }
    })
  }
  return output
}

const obj = {
  a: 1,
  b: [
    {
      b1: 'b1',
      b2: {
        b2_1: 'b2_1'
      }
    }
  ]
}

const clone = deepClone(obj)

obj.b = { b: 'b' }

console.log(clone)
console.log(obj)
summarychm

summarychm commented on May 11, 2020

@summarychm
// WeakMap + new obj.constructor() 
// 考虑了 Data,RegExp,循环引用,没处理Symbol,Set,Map等
function deepClone(obj, hash = new WeakMap()) {
  if (obj === null || typeof obj !== "object") return obj; // 值类型
  if (obj instanceof RegExp) return new RegExp(obj); // RegExp类型
  if (obj instanceof Date) return new Date(obj); // Dete类型
  //! 以下是针对Object类型的处理逻辑
  if (hash.has(obj)) return hash.get(obj); // 防止循环引用
  const temp = new obj.constructor(); // 基于constructor创建新类
  hash.set(obj, temp); // 在WeakMap中缓存
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) // 递归处理自身属性
      temp[key] = deepClone(obj[key], hash);
  }
  return temp;
}
smile-2008

smile-2008 commented on Jan 15, 2021

@smile-2008

为什么要进行拷贝

var obj1={
    value: 'a'
}
var obj2 = obj1;
obj2.value='b';
console.log(obj1);//{ value: 'b' }

因为对象是引用类型,所以赋值时的操作仅是赋予相同的地址,当对其中一个对象进行操作时,就会影响其他的对象。解决这个问题就需要拷贝了。

浅拷贝:

使用原生的Object.assign() 方法就可以实现浅拷贝

var obj1={
    value: 'a'
}
var obj2 = Object.assign({},obj1);
obj2.value='b';
console.log(obj1);//{ value: 'a' }

但是如果拷贝的源对象当中包含对象时,OBject.assign()方法只会拷贝对象的引用地址

var obj1={
    value: 'a',
    obj3:{
        value2: 'c'
    }
}
var obj2 = Object.assign({},obj1);
obj2.obj3.value2='b';
console.log(obj1);//{ value: 'a', obj3:{ value2: 'b' } }

深拷贝

如果要拷贝的对象中包含对象,就需要深拷贝了,一般使用原生的方法JSON.parse(JSON.stringify(obj))

j1={
    value: 'a',
    obj3:{
        value2: 'c'
    },
    arr:[1,2,3]
}
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.obj3.value2='b';
obj2.arr[0]= "a";
console.log(obj2);//{ value: 'a', obj3:{ value2: 'b' }, arr:['a',2,3] }
console.log(obj1);//{ value: 'a', obj3:{ value2: 'c' }, arr:[1,2,3] } 没有发生改变

实现一个对数组和对象的深拷贝的方法

var obj={
    name: 'znl',
    age: 18,
    friend:{
        name: 'borys',
        age: 20
    },
    arr:[1,2,[3,4]]
}

function copy(obj){
    var type=Object.prototype.toString.call(obj);
    if(!(type == '[object Array]' || type == '[object Object]')){
        return 'Type Error!';
    }
    return JSON.parse(JSON.stringify(obj));
}

var obj2= copy(obj);
console.log(obj.friend === obj2.friend)//false
console.log(obj.arr === obj2.arr)//false

参考:

xiaoqiangz

xiaoqiangz commented on Jun 17, 2022

@xiaoqiangz

由于对象是引用类型,对于赋值的操作只是赋予相同的地址,当对其中的一个对象进行操作时,另外一个对象也会改变。解决这个问题就需要拷贝了。
浅拷贝:Object.assign可以实现浅拷贝,只会拷贝对象的引用地址。
深拷贝:对象和数组都可以
var result = {}
var res = (function(_) {
var types = 'String Null Undefind Date RegExp Object Array Boolean'.split(' ')
function type() {
return Object.prototype.toString.call(this).slice(8, -1)
}
for(var i=0;i<types.length;i++){
_['is'+types[i]] = (function(){
return function(ele) {
return type.call(ele)
}
})(types[i])
}
return _
})(result)
function deepClone(target){
let result
if (res.isArray(target) === 'Array') {
result = []
for(let o in target) {
result.push(deepClone(target[o]))
}
}else if(res.isObject(target) === 'Object') {
result = {}
for(let o in target) {
result[o] = deepClone(target[o])
}
} else { // 基本数据类型
result = target
}
return result
}
let originData = deepClone(origin)
origin.b[1] = 6
console.log(origin)
console.log(originData)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    jsJavaScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @smile-2008@summarychm@haizhilin2013@Cyrusky@xiaoqiangz

        Issue actions

          [js] 第71天 说说你对深浅拷贝的理解?并实现一个对数组和对象深拷贝的方法 · Issue #504 · haizlin/fe-interview