1. 数据类型
- 基本类型:Number、String、Boolean、Null、Undefind、Symbol、BigInt。
- 引用类型:Objetc、Function、Array、Date
2.栈和堆的理解
- 栈是自动分配相对固定大小的内存空间,并由系统自动释放。
- 堆是动态分配内存,内存大小不一,也不会自动释放。
- 栈内存:存储基本类型值和指定代码的环境。
- 堆内存:存储引用类型值的空间。
3.基本类型
基本类型值,在赋值、浅拷贝、深拷贝时都是复制基本类型的值给新的变量,之后二个变量之间操作不在相互影响,在两个不栈内存中。
let a = 10;
let b = a;
b = 11;
console.log(a);
//10
console.log(b);
//11
4.引用类型
引用类型的值是同时保存在栈内存和堆内存中。
4.1 赋值,两个变量指向同一个地址,一个变量值改变时,另一个同样改变。
let c = {name:"学习数据类型"};
let d = c; //其实只是c变量的内存地址赋值给d变量
console.log(c,d);
//{name: '学习数据类型'} {name: '学习数据类型'}
d.name = "学会了";
console.log(c,d)
//{name: '学会了'} {name: '学会了'}
4.2 浅拷贝,得到一个新的变量,这个对象有着原始对象属性值的一份精确拷贝。
- 如果属性是基本类型,拷贝的就是基本类型的值。
- 如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
let e = { name:"小明",child: { interest: "篮球"}};
let f = {...e}; //通过解构浅拷贝
f.name = "小黄"; // 修改基本类型互不影响
f.child.interest = "足球"; //修改child对象,引用类型会影响
console.log(e,f);
常用的浅拷贝有:数组slice、concat、Array.from(), Object.assign({},obj)。
4.3 深拷贝,得到一个全新变量,它的改变不会影响原对象。
使用基础版实现深拷贝 JSON.parse(JSON.stringify(obj));
Symbol、Function、undefined、正则、 Date 不起效果
let obj1 = {name:"学习引用类型"};
let obj2 = JSON.parse(JSON.stringify(obj1));
使用递归实现对象深拷贝
let obj = {
a: 1,
b: "学习深拷贝",
c: function(){},
d: /\d/,
e: new Date(),
f: { dd: 12},
g: Symbol(1),
h: undefined,
i: [1,2,{ c: 3 }]
}
function deepClone(obj){
if(obj === null) return null; //因为typeof(null)也是Object
if(typeof(obj) !== "object"){ //非Object类型直接返回
return obj;
}
if(obj instanceof RegExp){
return new RegExp(obj); //返回新的正则
}
if(obj instanceof Date){
return new Date(obj); //返回Date
}
if(obj instanceof Function){
return new Function(obj) //返回函数
}
if(obj instanceof Symbol){
return new Symbol(obj) //返回Symbol
}
let newObj = new obj.constructor;
for(let key in obj){
if(obj.hasOwnProperty(key)){
newObj[key] = this.deepClone(obj[key])
}
}
return newObj;
}
let deepCopyObj = deepClone(obj);
console.log(deepCopyObj)