JS中的深拷贝和浅拷贝
浅拷贝
浅拷贝是拷贝第一层的拷贝
使用Object.assign解决这个问题。
let a = {
  age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1
通过展开运算符 ... 来实现浅拷贝
let a = {
  age: 1
}
let b = {...a};
a.age = 2;
console.log(b.age)  // 1
深拷贝
简单的做法:JSON.parse(JSON.stringify(obj))
但是该方法也是有局限性的:
- 会忽略undefined
- 会忽略symbol
- 会忽略函数
- 不能解决循环引用的对象 (会抱错)
如果你所需拷贝的对象含有内置类型并且不包含函数,可以使用 MessageChannel
自封装深拷贝
思路:
- 使用for-in遍历对象
- 因为for-in会遍历原型链上的属性,所以需要判断属性是否在原型链上,不是原型链才拷贝
- 判断属性值类型是原始类型和引用类型
- 原始类型直接赋值(注意null)
- 引用类型判断是对象还是数组,创建对应的空对象或空数组,递归调用函数,将值赋值进去
/**
 * 深度克隆
 * @param   origin 被拷贝的原对象
 * @param   target 拷贝出来的对象
 * @return         拷贝出来的对象
 */
function deepClone(origin, target) {
  if(typeof(origin) !== 'object' || origin) {
    return origin;
  }
  target = target || {};
  for(let prop in origin) {   //使用 for-in
    if(origin.hasOwnProperty(prop)) { //不是原型链上的
      if(typeof(origin[prop]) === 'object' && origin[prop] ) { //是对象
        // 先判断是不是数组
        if(origin[prop] instanceof Array) {
          target[prop] = [];
          deepClone(origin[prop], target[prop]);
        } else {
          target[prop] = {};
          deepClone(origin[prop], target[prop]);
        }
      } 
      else {
        target[prop] = origin[prop];
      }
    }
  }
  return target;
}
深拷贝 - BFS
// 如果是对象/数组,返回一个空的对象/数组,
// 都不是的话直接返回原对象
function getEmptyArrOrObj(item) {
  let itemType = Object.prototype.toString.call(item) 
  if(itemType === '[object Array]') {
    return []
  }
  if(itemType === '[object Object]') {
    return {}
  }
  return item
}
function deepCopyBFS(origin) {
  const queue = []
  const map = new Map() // 记录出现过的对象,处理环
  let target = getEmptyArrOrObj(origin)
  if(target !== origin) {
    // 说明origin是一个对象或数组,需要拷贝子代
    queue.push([origin, target]);
    map.set(origin, target)
  }
  while(queue.length) {
    let [ori, tar] = queue.shift(); // 出队
    for(let key in ori) {
      if(ori.hasOwnProperty(key)) { // 不在原型上
        if(map.get(ori[key])) { // 处理环
          tar[key] = map.get(ori[key])
          continue
        }
        tar[key] = getEmptyArrOrObj(ori[key]);
        if(tar[key] !== ori[key]) {
          queue.push(ori[key], tar[key])
          map.set(ori[key], tar[key])
        }
      }
    }
  }
  return target
}
深拷贝 - DFS
function deepCopyDFS(origin){
	let stack = [];
	let map = new Map(); // 记录出现过的对象,用于处理环
	let target = getEmptyArrOrObj(origin);
	if(target !== origin){
		stack.push([origin, target]);
		map.set(origin, target);
	}
	while(stack.length){
		let [ori, tar] = stack.pop();
		for(let key in ori){
      if(ori.hasOwnProperty(key)) { // 不在原型上
        // 处理环状
        if(map.get(ori[key])){
          tar[key] = map.get(ori[key]);
          continue;
        }
        tar[key] = getEmptyArrOrObj(ori[key]);
        if(tar[key] !== ori[key]){
          stack.push([ori[key], tar[key]]);
          map.set(ori[key], tar[key]);
        }
      }
		}
	}
	return target;
}
    今天你学习了吗!!!

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号