首先我们知道在JavaScript当中数据类型分为基本数据类型和引用数据类型
1.基本数据变类型
:基本数据类型是指直接存放在栈当中的简单数据 数据大小确定 它们是直接按值存放 可以直接按值访问
var a = 10;
var b = a;
b = 20;
console.log(a)//10;
console.log(b)//20
2.引用数据类型
引用数据类型是存放在堆内存里的对象,变量其实在栈中保存的是一个指针(指向堆内存的一个引用地址)通过这个指针可以快速找到在保存在堆内存的对象
举例说明
var obj1 = new object()
var obj2 = obj1
obj2.name = "我添加了一个name"
console.log(obj1.name) //打印结果为“我添加了一个name”
我们发现obj2改变时obj1也发生了改变是因为 obj1赋值给obj2的只是一个引用地址 他们任然共享的是一个堆内存 所以修改obj2也是在修改obj1
我们将这种拷贝方式叫做引用拷贝
引用拷贝指的是二者都是指向的是同一个对象并未创建一个新的对象 当其中一个对象发生改变时另外一个对象也会发生改变
浅拷贝
而浅拷贝和引用拷贝不同 浅拷贝是按位拷贝
浅拷贝的实现方式
var obj = {
name : "xia",
age : 18,
arr : [1,2,3]
}
//浅拷贝给obj2
var obj2 = Object.assign({},obj)
obj2.arr.push(4)
obj2.name = "XiaRongwu"
console.log(obj)
console.log(obj2)
此时我们分别打印obj 和obj2的值结果为
我们发现在修改obj2里的基本数据类型时obj并不会改变 而修改引用类型数据arr的时候修改obj2 obj也随之改变了
为什么会出现这种现象呢?
是因为浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝
如果属性是基本类型,拷贝的就是基本类型的值;
如果属性是引用类型,拷贝的就是内存地址(即复制引用但不复制引用的对象) ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。
浅拷贝的实现方式
使用object.assin()【es6新增】
使用…运算符 原理和object.assin()一样
【要注意的一点就是如果对象的值都是基本数据类型的话那就是深拷贝了】
使用Array.prototype.slice方法
示例
let a = [0, "1", [2, 3]];
let b = a.slice(1);
console.log(b);
// ["1", [2, 3]]
a[1] = "99";
a[2][0] = 4;
console.log(a);
// [0, "99", [4, 3]]
console.log(b);
// ["1", [4, 3]]
可以看出,改变 `a[1]` 之后 `b[0]` 的值并没有发生变化,但改变 `a[2][0]` 之后,相应的 `b[1][0]` 的值也发生变化。
说明 `slice()` 方法是浅拷贝,相应的还有`concat`等,在工作中面对复杂数组结构要额外注意。
深拷贝
当我们如果不想要父子对象之间产生联系 我们靠浅拷贝是不能满足的 因此我们就要使用深拷贝
深拷贝的含义
深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。拷贝前后两个对象互不影响。
简而言之就是
深拷贝会新创建一个堆内存来存放一个一模一样的对象 新旧对象户不干涉
如何实现深拷贝
1.使用JSON.parse(JSON.stringify())
最简单的方法就是用JSON.parse(JSON.stringify())
var a = {
age : 18,
like :{
readBook: "小学语文",
play:"篮球"
}
}
var b = JSON.parse(JSON.stringify(a))
console.log(b)
b.like.play = "乒乓球"
console.log(a)