mishe / blog

前端碰上的问题或体会
230 stars 39 forks source link

JS深拷贝碰到的问题 #155

Open mishe opened 7 years ago

mishe commented 7 years ago

js的数据类型有:Null Undefined Boolean Number Array String Object 之分,es6后又增加了Symbol, 其中分为2大类:基本数据类型和对象类型,同时产生了相应的2个传值方式:赋值和引用;

基本数据类型的深拷贝

JSON.parse(JSON.stringify(obj))

通过简单函数

function extendCopy(p) {
  var c = {};
  for (var i in p) {
    c[i] = p[i];
  }
  return c;
}

引用类型深拷贝

引用类型细分

严格来说,这些对象赋值时都是要考虑的,但常见的对象内部存放的数据类型不会涵盖的这么全面, 但也需要考虑:正则,函数,对象,数组,Dete,Dom

数据类型的识别办法

var type=Object.prototype.toString.call(Obj).split(/[\[\s\]]/)[2]

通过识别type可以确认数据的类型,然后分别针对Array,Object做不同的处理

let obj1 = {
  a: 11,
  b: 'bb',
  c: new Date(),
  d: function aa () {return 2},
  e:[1,2,3],
  f:new Error('error'),
  g:document.body,
  h:new RegExp(/[111]/)
}
function deepCopy (obj) {
  var type = Object.prototype.toString.call(obj).split(/[\[\s\]]/)[2];
let temp = type === 'Array' ? [] : type=='Object'? {}:obj;
if(type=='Array' || type=='Object'){
  for (let val in obj) {
    temp[val] = typeof obj[val] == 'object' ? deepCopy(obj[val]) : obj[val]
  }
}
  return temp
}

如上,实现了深拷贝

但深拷贝还有一个坑要填

那就是循环赋值问题;回到前面的

··· let obj1 = { a: 11, b: 'bb', c: new Date(), d: function aa () {return 2}, e:[1,2,3], f:new Error('error'), g:document.body, h:new RegExp(/[111]/), } obj1.g=obj1 deepCopy(obj1)

//Uncaught RangeError: Maximum call stack size exceeded at RegExp.[Symbol.split] () at String.split (native) at deepCopy (:12:50) at deepCopy (:16:47) at deepCopy (:16:47) at deepCopy (:16:47) at deepCopy (:16:47) at deepCopy (:16:47) at deepCopy (:16:47) at deepCopy (:16:47) ···

这是就会出现堆栈溢出的错误了。