# 浅拷贝与深拷贝

# 数据类型

数据可分为基本数据类型和引用数据类型

  • 栈:基本数据类型(Undefined, Null, Boolean, Number, String),直接存储在栈中的数据
  • 堆:引用数据类型(对象、数组、函数),在栈中的存储指针,当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后,从堆中获得实体。

基本数据类型:占据的空间小,大小固定,频繁被使用的数据,所以存储在栈中 引用数据类型:占据的空间大,大小不固定

# 浅拷贝与深拷贝

浅拷贝与深拷贝只针对引用数据类型(array, object, function)

浅拷贝只复制指向的某个指针, 而不复制对象本身,新旧对象共享一个内存 深拷贝会创造一个一模一样的对象,新对象与原对象不共享内存,修改新对象不会改到原对象(指针指向不同堆地址)

# 赋值和浅拷贝的区别

  • 当把一个对象赋值给一个新的对象时,赋的是栈中的地址,而不是堆中的数据。也就是两个对象指向同一个存储空间,即无论哪一个改变,存储空间的值会改变,两个对象是联动的
  • 浅拷贝是按位拷贝对象,它会创建一个新的对象,这个对象有原对象属性值的精确拷贝,如果属性是基本类型,拷贝的就是基本类型的值,如果属性是存储地址(引用类型),则拷贝的是引用地址。因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即默认拷贝改造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源
var obj1={
  "name": "hai",
  "age": 18,
  "language": [1, [2,3], 4]
}
var obj3 = shallowCopy(obj1);
obj3.name="lisa";
obj3.language[1]= 5;
function shallowCopy(src){
  var dis={};
  for(var key in src){
    if(src.hasOwnProperty(key)){
      dis[key] = src[key]
    }
  }
  return dis;
}
console.log({obj1})
console.log({obj3})
// obj1 name 未变,language受obj3影响改变了

# 浅拷贝的实现方式

# 1 Object.assign()[当 object 只改变一层的时候是深拷贝,其他时候是浅拷贝]

let obj={
  username: "koko"
};
let obj2 = Object.assign({}, obj);
obj2.username = "baba";
console.log(obj) // {username: "koko"}
let obj0 = {a: {username: "koko"}}
let obj02 = Object.assign({}, obj0);
obj02.a.username = "kaka";
console.log(obj0) // {a: {username: "kaka"}}

# 2 Array.prototype.concat()

let arr =  [1,2,{name: "koba"}];
let arr2 = arr.concat();
arr2[2].name = "coco";
console.log(arr) // [1,2,{name: "coco"}];

# 3 Array.prototype.slice()

let arr =  [1,2,{name: "koba"}];
let arr2 = arr.slice();
arr2[1] = 44;
console.log(arr) // [1,2,{name: "koba"}] 原数组不变
// arr2[2].name = "coco"; // 原数组会改变
// console.log(arr) // [1,2,{name: "coco"}];

# 深拷贝方法

# 1 JOSN.parse(JSON.stringify(obj)) 【不能成立函数】

json 变字符串,字符串变 json,新的对象产生,开辟一个新的栈

# 2 手写递归方法

// 定义检测数据类型的功能函数
function checkedType(target){
  return Object.prototype.toString.call(target).slice(8, -1)
}
function clone(target){
  let result, targetType = checkedType(target);
  if(targetType === "Object"){
    result={}
  } else if(targetType === "Array"){
    result = []
  } else {
    return target
  }
  for(let i in target){
    let value = target[i]
    if(checkedType(value) === "Object" || checkedType(value) === "Array"){
      result[i] = clone(value)
    } else{
      result[i] = value;
    }
  }
  return result;
}

# 3 lodash 函数库

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