数据类型
(可以略过)在步入正文之前,我们得先了解以下,什么是基本数据类型
什么是引用数据类型
基本数据类型: Number、String、Boolean、Undefined、Null
栈(stack):栈会自动分配内存空间,会自动释放,存放基本类型,简单的数据段,占据固定大小的空间
引用数据类型: Object、Array、function、Date、RegExp
堆(heap):动态分配的内存,大小不定也不会自动释放,存放引用类型,指那些可能由多个值构成的对象,保存在堆内存中,包含引用类型的变量,实际上保存的不是变量本身,而是指向该对象的指针
我对声明变量与赋值的理解:当声明了一个变量时就已经使用了栈内存(此时并没有赋值),那么值是
undefined
,并且声明变量发生在编译期
,而赋值是在执行期
1.基本数据类型
使用=
赋值时,基本数据类型执行的是复制
操作
解析:声明变量a,并且赋值100(创建一个内存空间),声明变量b,并且赋值a(此时a的数据为100,上面有提到基本数据类型在赋值过程中执行的是复制操作)所有现在把a的100复制出来,给到b那么b(创建一个内存空间)此时两个内存空间没有任何关系,随后又把90赋给了a(90)a的数据已经更改,而b是另一个内存空间,并未被修改。
1 | var a = 100; |
2.引用数据类型
使用=
赋值时,引用数据类型执行的是引用(指向)
操作
解析: 声明old时初始化了数据{name:'lete114',age:18}
(创建内存空间),随后声明obj将old赋值给obj(此时并不是创建新的内存空间,而是把obj指向到了old的内存空间)所有他们两个是有关系的,当修改了name属性和age属性时,由于obj指向old的内存空间,old发生改变后obj也能获取到改变后的值
1 | var old = {name:'lete114',age:18} |
正文
扯了那么长的大水文,终于到正文了,为什么非要说数据类型呢?这关系到本文的内容,只为更详细的记录每一个知识点,如有错误,请各位大佬在评论区留言
问:什么是拷贝?
把A的数据赋值给B,当B改变内容后,观察A的内容是否改变,如果改变则:浅拷贝|反之深拷贝
可以理解为:基本类型自带深拷贝,引用类型自带浅拷贝
浅拷贝
浅拷贝的几种方法(浅拷贝只能拷贝第一层的内容,无法往下递归)
- 通过赋值引用的方式(我也不知道这算不算拷贝,因为已经变成另一个变量调用了,所有我认为是拷贝)COPY
1
2
3
4
5
6
7
8
9
10
11
12var old = {name:'lete114',age:18}
var obj = old
old.name='Lete乐特'
old.age=20
console.log(old) // {name:'Lete乐特',age:20}
console.log(obj) // {name:'Lete乐特',age:20}
obj.name='Lete乐特真帅'
obj.age=20
console.log(old) // {name:'Lete乐特真帅',age:20}
console.log(obj) // {name:'Lete乐特真帅',age:20} - 通过扩展运算符(es6)COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 定义一个对象
const oldObj = {
name:'lete114',
age:18,
friend:{
name: '小明',
age:18
}
}
// es6扩展运算符浅拷贝
let newObj = {...oldObj}
// 修改属性值
newObj.name = '乐特'
newObj.age = 20
newObj.friend.name = '小李'
newObj.friend.age = 20
console.log(oldObj)
console.log(newObj) - 通过
Object.assign()
方法(es5)COPY1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 定义一个对象
const oldObj = {
name:'lete114',
age:18,
friend:{
name: '小明',
age:18
}
}
// es5 Object.assign()方法浅拷贝
let newObj = Object.assign({},oldObj)
// 修改属性值
newObj.name = '乐特'
newObj.age = 20
newObj.friend.name = '小李'
newObj.friend.age = 20
console.log(oldObj)
console.log(newObj) - 通过for循环重新赋值COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// 定义一个对象
const oldObj = {
name:'lete114',
age:18,
friend:{
name: '小明',
age:18
}
}
// 定义空对象
let newObj = {}
// for循环重新赋值浅拷贝
for (const key in oldObj) {
newObj[key] = oldObj[key]
}
// 修改属性值
newObj.name = '乐特'
newObj.age = 20
newObj.friend.name = '小李'
newObj.friend.age = 20
console.log(oldObj)
console.log(newObj)
深拷贝
- 通过JSON.stringify()和JSON.parse()方法COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// 定义一个对象
const oldObj = {
name: 'lete114',
age: 18,
friend: {
name: '小明',
age: 18
}
}
// 通过JSON.stringify()和JSON.parse()方法
function DeepClone(old) {
let str = JSON.stringify(old) // 将对象转换为字符串了(变为基本类型)
let obj = JSON.parse(str) // 将字符串解析为对象(变为了引用类型)
return obj
}
let newObj = DeepClone(oldObj)
// 修改属性值
newObj.name = '乐特'
newObj.age = 20
newObj.friend.name = '小李'
newObj.friend.age = 20
console.log(oldObj)
console.log(newObj) - 深拷贝可以拷贝全部,无限递归COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38// 定义一个对象
const oldObj = {
name:'lete114',
age:18,
friend:{
name: '小明',
age:18
}
}
// 定义一个空对象
let newObj = {}
DeepClone(oldObj,newObj)
function DeepClone(oldObj,newObj){
// 循环获取对象
for(let key in oldObj){
// 将旧的对象值赋给value
let value = oldObj[key]
// 判断是否属于数组
//(Array必须在Object之前判断,因为Array的底层继承的是Object,如果Object在前面判断的话,当遇到Array时也会被视为Object)
if (value instanceof Array){
newObj[key] = [] // 将array类型赋给新对象
DeepClone(value,newObj[key]) // 重新调用
}else if(value instanceof Object){
newObj[key] = {}
DeepClone(value,newObj[key])
}else{
newObj[key] = value
}
}
}
newObj.name = '乐特'
newObj.age = 20
newObj.friend.name = '小李'
newObj.friend.age = 20
console.log(oldObj)
console.log(newObj)