一、栈和堆
概念
栈:一般用来存变量名和地址,空间小,不可修改
堆:一般用来存值(变量的值...如)空间大,可修改
关系
1.一一对应:一个栈对应一个堆
2.多对一:多个栈对应一个堆
存取规则
栈:先进后出
堆:先进先出
二、数据类型分类
1.基本类型:
特点:
1. 数据存在栈中,默认深拷贝,改变新的(b)不影响老的(a)
2. 变量名和值都存在栈中,值就是地址地址就是值
如:var a=10;var b=a;b=20;console.log(a)//10,console.log(b)//20
除了对象、数组、函数都是基本类型
引用类型
特点:
1.栈中只保存了地址(变量名),该地址指向堆中的某个数据(既该地址(变量名)所对应的值保存在堆中)
2.默认浅拷贝,只复制地址(变量名,属性名),没有复制值,改变新的(o2.name)影响老的(o1.name)
3.数组函数对象都是引用类型的数据
var o1={name:"zhangsan"};
var o2=o1;
o2.name="lisi";
console.log(o2.name) //lisi
console.log(o1.name) //lisi
三、深浅拷贝
浅拷贝:只复制地址(变量名)栈中存的数据
深拷贝:既复制栈中数据也复制堆中数据
引用数据类型如对象默认浅拷贝
var o1={name:"zhangsan"};
var o2=o1;
此时o1,o2这两个栈中的数据同时指向同一个堆,(o1的{name:"zhangsan"}),
设置o2.name="lisi"后o1,o2还是同时指向这个堆,所以原来的o1的值也被改变了
四、引用数据类型(对象,数组函数)实现深拷贝的方法
**浅拷贝 复制的是地址而非具体的值**
let obj1 = { a: 1, b: 2 };
let obj2 = obj1;
obj2.a = 11;
console.log(obj1); //{ a: 11, b: 2 }
深拷贝的实现:通过遍历原对象拷贝地址和值放入新对象,此时obj1,obj2指向两个不同的堆,改变obj2的值不会影响obj1的值
let obj1 = { a: 1, b: 2 };
let obj2 = {};
for (let i in obj1) {
obj2[i] = obj1[i];
}
obj2.a = 11;
console.log(obj1); //{ a: 1, b: 2 }
以上存在问题:原对象的值仍然是一个引用对象时,for-in只实现了一层深拷贝,obj1和obj2指向不同的堆地址,但是他两的属性a的值仍然是共用的[1],改变obj2的a的值仍然会影响obj1的a的值
let obj1 = { a: [1], b: 2 };
let obj2 = {};
for (let i in obj1) {
obj2[i] = obj1[i];
}
console.log(obj2);//{ a: [1], b: 2 }
console.log(obj1);//{ a: [1], b: 2 }
obj2.a[0] = 11;//会有影响
console.log(obj1); { a: [11], b: 2 }
解决方案一
// 加判断利用递归思想,如果仍然是引用数据类型继续遍历
let obj1 = { a: [1], b: 2 };
function deepCopy(obj) {
// 如果传进来的将要被拷贝的数据是数组则创建一个新的空数组
// 注意数组instanceof检测也是对象不能判断究竟是对象还是数组,所以条件写Arraaay
if (obj instanceof Array) {
var newObj = [];
} else { //如果传进来的将要被拷贝的数据是对象则创建一个新的对象
var newObj = {};
}
// 遍历旧的对象,判断如果对象的某个键对应的值的数据类型是对象,则把obj[i]作为参数再执行deepCopy(obj),
// 相当于遇见旧对象的值还是对象时让新的obj2的某个键(再创建一个新对象79行)再调用函数再进行一次深拷贝,依次
// 进行逐层进行深拷贝(递归),直到 旧对象的值的数据类型全不是object,深拷贝结束,返回新的对象
for (let i in obj) {
if (typeof obj[i] == "object") {
newObj[i] = deepCopy(obj[i]);
} else {
newObj[i] = obj[i];
}
}
return newObj;
}
let obj2 = deepCopy(obj1);
解决方案二
let obj1 = { a: [1], b: 2 };
let obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj2);
obj2.a[0] = 11;
console.log(obj1);