深拷贝、浅拷贝、赋值


前端数据类型分为两种值类型(String, Number, Boolean, Null, Undefined,Symbol)和引用类型(Array,Function,Object)。

值类型:数据存储在栈中。

引用类型:栈中存储的是对数据的引用地址(指针),真实数据存储的堆内存中。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

e.g 出去团建,员工门卡自己保管(值类型),老板门卡统一由秘书保管(引用类型)。

深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。

浅拷贝:只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存

深拷贝:会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

e.g旅行社来了个新顾客:

加入现有旅行团,多印一份该团的出行指南(浅拷贝)

给他单独设计一份出行规划(深拷贝)

赋值和浅拷贝的区别

赋值: 赋的其实是该对象的在栈中的地址,而不是堆中的数据。e.g 修改原/新对象值类型属性的取值后,另外一个对象值也会被改掉。

浅拷贝:浅拷贝拷贝的是指针而非值,是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址e.g 修改修改原/新对象值类型属性的取值后,另外一个对象不受影响。

// 对象赋值
var obj1 = {
   'name' : 'zhangsan',
   'age' :  '18',
   'language' : [1,[2,3],[4,5]],
};
var obj2 = obj1;
obj2.name = "lisi";
obj2.language[1] = ["二","三"];
console.log('obj1',obj1)
console.log('obj2',obj2)

// 浅拷贝
var obj1 = {
   'name' : 'zhangsan',
   'age' :  '18',
   'language' : [1,[2,3],[4,5]],
};
var obj3 = shallowCopy(obj1);
obj3.name = "lisi";
obj3.language[1] = ["二","三"];
function shallowCopy(myObj) {
   var dst = {};
   for (var prop in myObj) {
       if (myObj.hasOwnProperty(prop)) {
           dst[prop] = myObj[prop];
       }
   }
   return dst;
}
console.log('obj1',obj1)
console.log('obj3',obj3)

浅拷贝实现方法:

1.Object.assign() 对象合并

let obj = {username: 'kobe'};
var initalObj = Object.assign({}, obj);

2.Array.prototype.concat() 数组合并

let arr = [1, 3, {username: 'kobe'}];
let arr2=arr.concat();  

3.Array.prototype.slice() 数组提取

let arr = [1, 3, {username: ' kobe'}];
let arr3 = arr.slice();  //备注:不指定参数

 4.解构赋值  {...obj }

深拷贝的实现方法:

1.JSON.parse(JSON.stringify())  仅可以处理数组和对象,不能处理函数

2.使用函数库 Lodash 

_.cloneDeep 用来做 Deep Copy

var _ = require('lodash');
var obj1 = {
   a: 1,
   b: { f: { g: 1 } },
   c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);        // false

3.原生js实现深拷贝代码

// 深拷贝
        function clone(data){
            if(data instanceof Array){  // 传入为数组类型
                var res = [];
                for(var i=0;i){
                    res[i] = clone(data[i]);
                }
                return res
            }
            else if(data instanceof Object){    // 传入为对象类型
                var res = {};
                for(var key in data){
                    res[key] = clone(data[key]);
                }
          return res }
else{ return data; // 传入为数字或字符串 } }