zoukankan      html  css  js  c++  java
  • 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

    自封装深拷贝
    思路:

    1. 使用for-in遍历对象
    2. 因为for-in会遍历原型链上的属性,所以需要判断属性是否在原型链上,不是原型链才拷贝
    3. 判断属性值类型是原始类型和引用类型
    4. 原始类型直接赋值(注意null)
    5. 引用类型判断是对象还是数组,创建对应的空对象或空数组,递归调用函数,将值赋值进去
    /**
     * 深度克隆
     * @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;
    }
    

    测试上面的两个 deepCopy

    今天你学习了吗!!!
  • 相关阅读:
    SP笔记:交叉实现七行并成一行
    HTML tag 学习
    操作哈希表
    Efficient bipedal robots based on passivedynamic walkers
    Pushing People Around
    ZEROMOMENT PONTTHIRTY FIVE YEARS OF ITS LIFE

    Active Learning for RealTime Motion Controllers
    Accelerometerbased User Interfaces for the Control of a Physically Simulated Character
    Dynamic Response for Motion Capture Animation
  • 原文地址:https://www.cnblogs.com/nayek/p/11749911.html
Copyright © 2011-2022 走看看