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

    今天你学习了吗!!!
  • 相关阅读:
    shapely and geos break在distance方法
    linux运维
    【未完待补充】linux 设置So动态库链接路径
    用python建立最简单的web服务器
    nginx + keepalived 双机热备
    nagios监控linux主机监控内存脚本
    linux普通用户权限设置为超级用户权限方法、sudo不用登陆密码
    zato server启动后自动关闭问题解决
    Linux下几种文件传输命令 sz rz sftp scp
    python风味之大杂烩
  • 原文地址:https://www.cnblogs.com/nayek/p/11749911.html
Copyright © 2011-2022 走看看