js deep copy of the final solution

The solution provided herein javascript deep copy, can handle multiple nested array, function, Date, RegExp, null, undefined, prototype chain, are treated like a circular reference.

I believe we have learned the concept of deep copy and shallow copy of JavaScript. For deep copy, we used JSON "serialize + deserialization" way to solve, but

Since JSON.parse (JSON.stringify ()) deep copy will have the following questions:

对于 JSON.parse(JSON.stringify(data))

  • If the attribute is a time 1.data key objects, which will switch to the date string.
  • If the key property is 2.data RegExp, Error objects, which will be converted into an empty object {}
  • If the 3.data key attribute is undefined, functions or symbol, which is the property will be lost.
  • If within 4.data key attributes are NaN, Infinity and -Infinity, it will become null
  • If the properties of the custom key 5.data constructor generated conversion discards object constructor.
  • 6.data in case if there is a circular reference can not be achieved deep copy correctly.

The case of Example 1-5: 

function Person(name) {
  this.name = name;     
}      
Person.prototype.speak = function(){
  console.log('i can speak')
}
var arr1 =  {
  a:1,
  b:undefined,
  c:new Date('2019-12-24'),
  d:new Person('mily'),
  e:new RegExp('\\w+'),
  f:NaN,
  g:Symbol("foo"),
  h:{
    total:12,
    list:[{name:'小明',age:34},{name:'小红',age:23}]
  }
}
// JSON.parse(JSON.stringify())方式
console.log(JSON.parse(JSON.stringify(arr1))
//结果为
//{
//   a: 1
//   c: "2019-12-24T00:00:00.000Z"
//   d: {name: "mily"}
//   e: {}
//   f: null
//   h: {total: 12, list: Array(2)}
// }

Circular reference example

var obj1 = {
    x: 1, 
    y: 2
};
obj1.z = obj1;//循环引用
console.log(JSON.parse(JSON.stringify(arr1)))

Directly on the error. 

So JSON.parse (JSON.stringify (data)) is not a universal solution. However JSON.parse(JSON.stringify(data))simple and crude, has met 90% of the usage scenario. Therefore, only through " to solve the above problems recursive" function as follows:

/**
 * isType 判断数据类型
 * @param obj 要检验类型的数据,必填
 * @param type 要检验的数据类型,选填
 * @returns {String|Boolean} 返回对应数据格式的字符串,或者与type参数比较的布尔值
 */
const isType = function(obj, type) {
  // tostring会返回对应不同的标签的构造函数
  const toString = Object.prototype.toString
  const map = {
    '[object Boolean]': 'boolean',
    '[object Number]': 'number',
    '[object String]': 'string',
    '[object Function]': 'function',
    '[object Array]': 'array',
    '[object Date]': 'date',
    '[object RegExp]': 'regExp',
    '[object Undefined]': 'undefined',
    '[object Null]': 'null',
    '[object Object]': 'object'
  }
  if (obj instanceof HTMLElement) {
    return type ? type === 'element' : 'element'
  }
  return type ? type === map[toString.call(obj)] : map[toString.call(obj)]
}
/**
 * clone 对象或数组的拷贝函数
 * @param obj 要拷贝的数据(对象/数组)
 * @returns {Object/Array} 返回对象或数组
 */
const clone = function(obj, parent = null) {
  //parent用于递归循环引用爆栈处理
  // 创建一个新对象
  let result = new obj.constructor() //保持继承链
  let keys = Object.keys(obj),
    key = null,
    temp = null,
    _parent = parent
  // 该字段若有父级则需要追溯该字段的父级
  while (_parent) {
    // 如果该字段引用了它的父级则为循环引用
    if (_parent.originalParent === obj) {
      return _parent.currentParent // 循环引用直接返回同级的新对象
    }
    _parent = _parent.parent
  }
  for (let i = 0; i < keys.length; i++) {
    key = keys[i]
    temp = obj[key]
    if (temp && isType(temp) === 'date') {
      result[key] = new Date(temp)
      continue
    }
    if (temp && isType(temp) === 'regExp') {
      result[key] = new RegExp(temp)
      continue
    }
    // 若字段的值是一个对象/数组
    if (temp && (isType(temp) === 'object' || isType(temp) === 'array')) {
      // 递归执行深拷贝 将同级的待拷贝对象与新对象传递给 parent 方便追溯循环引用
      result[key] = clone(temp, {
        originalParent: obj,
        currentParent: result,
        parent: parent
      })
    } else {
      result[key] = temp
    }
  }
  return result
}

Or the use of the above-described operation example, the user may be output before arr1 replication, and clone (arr1) for comparison after copying, and found that the data format is not lost completely.

console.log(arr1,clone(arr1))

 The user can also manually verify: var copydata modify certain attributes of the copied = clone (arr1) and found not to modify arr1. Truly a deep copy.

The above isType () function can be used to determine the type of data, you can use the common function on the positive!

First practiced hand, if there are errors and optimize positive place please correct me.

发布了1 篇原创文章 · 获赞 5 · 访问量 79

Guess you like

Origin blog.csdn.net/liao_yii/article/details/103924574