JS 基本数据类型和引用数据类型的区别及浅拷贝和深拷贝
1.栈(stack)和堆(heap)
栈(stack):
栈会自动分配内存空间,会自动释放,存放基本类型,简单的数据段,占据固定大小的空间。
堆(heap):
动态分配的内存,大小不定也不会自动释放,存放引用类型,指那些可能由多个值构成的对象,保存在堆内存中,包含引用类型的变量,实际上保存的不是变量本身,而是指向该对象的指针。
2.基本数据类型和引用数据类型
基本数据类型:
Number、String、Boolean、Null、Undefined、Symbol(ES6),这些类型可以直接操作保存在变量中的实际值特点:
1.占用空间固定,保存在栈中
当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,
这个方法的内存栈也将自然销毁了。因此,所有在方法中定义的变量都是放在栈内存中的;栈中存储的是基础变量以及一些对象的引用变量,
基础变量的值是存储在栈中,而引用变量存储在栈中的是指向堆中的数组或者对象的地址,这就是为何修改引用类型总会影响到其他指向这个地址
的引用变量)
2.保存与复制的是值本身
3.基本数据类型是指存放在栈中的简单数据段、数据大小确定、内存空间大小可分配、直接按值存放的,按值访问
4.引用数据类型存放在堆中
- 引用类型是存放在堆内存中的对象,变量其实是保存的在栈内存中的一个指针(保存的是堆内存中的引用地址),这个指针指向堆内存
- 引用类型数据在栈内存中保存的实际上是对象在堆内存中的引用地址。通过这个引用地址可以快速查找到保存中堆内存中的对象
var a = {
name: 'lily',
age: '16'
}
var b = a;
b.name = 'lokka';
console.log(a); // {name: "lokka", age: "16"}
把 a 赋值给 b ,就相当于把 a 的内存地址指向 b ,即 a 和 b 指向同一内存地址, 改变了 b 就相当于改变了 a
浅拷贝和深拷贝
1.概念:
浅拷贝: 只拷贝一层,深层次的对象级别只拷贝引用。
深拷贝: 拷贝多层,每一级别的数据都会被拷贝出来。
2.浅拷贝的实现方式
1.方法一:通用循环
function shallowCopy(obj) {
if (typeof obj !== 'object') return;
const newObj = obj instanceof Array ? [] : {};
for(let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}
2.方法二: Object.assign
const newObj = Object.assign({}, oldObj);
注:对象只有一层是深拷贝
let obj = {
name: 'lokka'
};
let obj2 = Object.assign({},obj);
obj2.name = 'cola';
console.log(obj);//{username: "lokka"}
3.方法三:Array.slice
const newArray = oldArray.slice();
4. 方法四:Array.concat
const newArray = oldArray.concat();
5.方法5: es6
const newObj = { ...oldObj};
const newArray = [ ...oldArray ];
深拷贝的实现方式:
1.通用循环
function deepCopy(obj) {
if (typeof obj !== 'object') return;
const newObj = obj instanceof Array ? [] : {};
for(let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}
2.方法二: JSON.parse、JSON.stringify
const newObj = JSON.parse(JSON.stringify(oldObj));