2

深拷贝与浅拷贝

基本类型的拷贝

先来看一段非常经典的代码

var a = 1;
var b = a;
a = 200;
console.log(a);      //200
console.log(b);      //1

我们应该知道基本类型“按值传递”,引用类型“按引用传递”,数值作为基本类型是保存在栈内存中,可以直接拿来用的,赋值是什么那么之后就一直是什么,不会受到传递元素的改变带来的影响,所以这里就不难理解上面的代码得到的值的原因了。

引用类型的拷贝

简单说,引用类型是生成一个指针保存的堆内存中,当给引用类型赋值时,我们写的内容是在栈内存中,也就是说我们拿到的其实是一个指针(不会直接拿到栈内存中的内容)。这个指针是指向栈内存中这个引用类型的代码。

浅拷贝针对对象中的基本类型的值生效,但是对引用类型中还有引用类型的情况就会失效。
所谓的深浅拷贝是相对与typeof === 'object' 而言的,数组是用堆对应保存的。
浅拷贝:拷贝了对象的存放地址,只是指向相同而已 (只解决了第一层,对象中还有对象就不适用了)
深拷贝:完全复制了一个独立的个体

  • 浅拷贝方法:(直接 =,Object.assign ...扩展运算符(对于对象一级属性是深拷贝,后面的属性都是浅拷贝)大部分都是浅拷贝)

=

 let arr1 = [1,3,5];
 let arr2 = arr1;
 arr1[0] = 10;
 console.log(arr2) // [10,3,5]
var obj1 = {
       name: '张三'
}

var obj2 = obj1;
obj2.name = '李四';

console.log(obj1.name); // '李四'

Object.assign

var obj1 = {
       name: '张三'
}

var obj2 = Object.assign({}, obj1);
obj2.name = '李四';
console.log(obj1.name);  // '张三'

至此,浅拷贝成功,但存在兼容性问题,比如低端的安卓机等,这个需要注意。但细心的朋友肯定会再做一个测试,如下:

var obj1 = {
       name: '张三',
       friends: {
          name: '刘备',
          age: 33
      }
}

var obj2 = Object.assign({}, obj1);
obj2.name = '李四';
obj2.friends.name = '关羽';
console.log(obj1.name);  // '张三'
console.log(obj1.friends.name);  // '关羽'

是的,到这一步,我们失败了,对象中嵌套对象时,Object.assign()只能拷贝一层,那如何解决呢?其实就要用到深拷贝的方法了:

var obj1 = {
       name: '张三',
       friends: {
          name: '刘备',
          age: 33
      }
}

var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = '李四';
obj2.friends.name = '关羽';
console.log(obj1.name);  // '张三'
console.log(obj1.friends.name);  // '刘备'
  • 深拷贝方法:

Json.parse(Json.stringify())

var obj1 = {
       name: '张三',
       friends: {
          name: '刘备',
          age: 33
      }
}

var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = '李四';
obj2.friends.name = '关羽';
console.log(obj1.name);  // '张三'
console.log(obj1.friends.name);  // '刘备'~~~~

lodash中的_.cloneDeep(value)方法

返回新数组方法 slice() 、 contat()、 map()(待实践)

  let arr1 = [2,5,7];
  let arr2 = arr1.slice(0);
  let arr3 = arr1.contat();
  let arr4 = arr1.map(x => x);
  arr2[0] = 4;
 arr1[0] = 99;
console.log(arr1,arr2) // [99,5,7]  [4,5,7] 

for-in连原型链也一并复制的方法 (待实践)

 let arr = [1,3,5];
 let arr2 = [] ;
 for(var key in arr) {
  arr2[key] = arr[key]
}

封装方法

   /**
     * 判断对象类型
     * @param {Object} object
     * @return {String} object type
     */
    getType(object) {
        var toString = Object.prototype.toString;
        var 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 (object instanceof Element) {
            return 'element';
        }
        return map[toString.call(object)];
    },
       /**
     * 对象的深度拷贝
     * @param data 需要拷贝的元数据
     * @return {any} 返回拷贝后的新数据
     */
    deepClone(data) {
        const type = this.getType(data);
        let obj;

        if (type === 'array') {
            obj = [];
        } else if (type === 'object') {
            obj = {};
        } else {
            //不再具有下一层次
            return data;
        }
        if (type === 'array') {
            for (let i = 0, len = data.length; i < len; i++) {
                obj.push(this.deepClone(data[i]));
            }
        } else if (type === 'object') {
            for (let key in data) {
                obj[key] = this.deepClone(data[key]);
            }
        }

        const constructor = data.constructor;
        if (constructor) {
            return Object.assign(new constructor(), obj);
        }
        return obj;
    },

guona
54 声望11 粉丝