一、数据类型
js中的数据类型:number、string、boolean、undefined、object、function、Symbol
根据各个类型的特性,我们会将这些类型分为两大类:基本类型、引用类型
基本类型:number、string、boolean、undefined、Symbol、null
引用类型:Array、Object、Function
二、基本类型和引用类型的区别
1、存储方式不同
存储数据的内存空间有两个:栈、堆
基本类型:将值直接存储在栈内存中
例:
let a = 1 // 基本类型的定义
在内存中:

引用类型:将值存储在堆中,将堆中存储数据的内存地址,存储在栈中
例:
let arr = [1, 2, 3] // 定义了引用类型
在内存中:

2、赋值时的操作不同
基本类型:将变量a赋值给变量b,是将变量a的值,复制一份,放在b栈空间中
例:
let a = 1 let b = a // 基本类型的赋值 a = 2 console.log(b) // 1
在内存中:

基本类型赋值后,改变其中一个的值,另一个的值没有被重新复制,所以另一个的值是不变的。
引用类型:将变量a的值赋值给变量b,将变量a在栈中存储的内存地址,复制了一份放在变量b的栈内存中了
例:
let arr = [1, 2, 3] let brr = arr
在内存中:

两个变来那个共享同一个堆内存,只要一个变量将其中的数据改变,另一个变量也就改变了。
3、比较方式不同
基本类型:
- 等于判断值是否相同,不比较类型
- 全等先判断类型是否相同,如果类型相同,才会判断其中的值是否相等
引用类型:
- 等于判断栈中存储的内存地址是否相同
- 全等先判断类型,类型相同再判断栈中内存地址的值是否相等
例:
基本类型:
let a = 1 let b = 1 console.log(a == b) // true console.log(a === b) // true
引用类型:
let arr = [1, 2, 3] let brr = [1, 2, 3] console.log(arr == brr) // false
三、深拷贝浅拷贝
基本类型太简单,没有深和浅的区别。所以深拷贝和浅拷贝针对的都是引用类型。
拷贝的原因:在某些操作中,我们需要一个跟原数据一模一样的数据,但希望原数据和新数据完全没有关联。
1、浅拷贝
原数据和新数据不共用同一个堆地址,但其中包含的引用类型数据还会共享同一个地址。
1.1、数组浅拷贝的方式
1.1.1、扩展运算
let arr = [
11,
{
name: '张三',
age: 12
},
33
]
let brr = [...arr]
console.log(arr === brr) // false ==> arr和brr没有共用同一个堆地址
console.log(arr[1] === brr[1]) // true ==> 其中包含的引用类型还共用同一个地址
浅拷贝只是将外层数据拷贝了一份新的,深层次数据还在关联,没有拷贝。
1.1.2、手动进行遍历
let arr = [
1,
[
2,
3
],
4
]
let brr = []
for (let a in arr) {
brr.push(arr[a])
}
console.log(arr === brr);// false
console.log(arr, brr);
console.log(arr[1] === brr[1]); // true
1.1.3、slice方法
let arr = [
1,
[
2,
3
],
4
]
let brr = arr.slice()
console.log(arr === brr);// false
console.log(arr, brr);
console.log(arr[1] === brr[1]); // true
1.1.4、concat方法
let arr = [
1,
[
2,
3
],
4
]
let brr = arr.concat()
console.log(arr === brr);// false
console.log(arr, brr);
console.log(arr[1] === brr[1]); // true
1.1.5、assign方法
let arr = [
1,
[
2,
3
],
4
]
let brr = Object.assign([], arr)
console.log(arr === brr);// false
console.log(arr, brr);
console.log(arr[1] === brr[1]); // true
1.2、对象的浅拷贝
1.2.1、手动遍历放在新对象中
let obj = {
name: '张三',
age: 12,
children: ['大毛', '二毛', '小明']
}
// 手动遍历
let pbj = {}
for(let key in obj) {
pbj[key] = obj[key]
}
console.log(pbj, obj);
console.log(pbj === obj); // false
console.log( obj.children === pbj.children );
1.2.2、扩展运算
let obj = {
name: '张三',
age: 12,
children: ['大毛', '二毛', '小明']
}
// 扩展运算
let pbj = {...obj}
console.log(pbj, obj);
console.log(pbj === obj);
console.log(pbj.children === obj.children);
1.2.3、assign方法
let obj = {
name: '张三',
age: 12,
children: ['大毛', '二毛', '小明']
}
// assign方法
let pbj = Object.assign({}, obj)
console.log(pbj, obj);
console.log(pbj === obj);
console.log(pbj.children === obj.children);
2、深拷贝
2.1、利用json转换
let arr = [
1,
[
2,
3
],
4
]
let brr = JSON.parse(JSON.stringify(arr))
console.log(arr === brr) // false
console.log(arr[1] === brr[1]) // false
注意:利用json转成进行深拷贝,如果原数据中包含函数,转换的时候会被忽略,函数是无法拷贝过来的。
2.2、手动封装递归函数实现深拷贝
function deepCopy(data) {
// 定义最终返回的数据,初始值为null(后面需要根据原数据的类型,决定这个数据的类型)
let newData = null
// 判断如果原数据是数组
if (Object.prototype.toString.call(data) === '[object Array]') {
newData = [] // 最终返回的数据也应该是数组
} else if (Object.prototype.toString.call(data) === '[object Object]') { // 原数据是对象
newData = {} // 最终返回的数据也应该是对象
} else {
// 原数据既不是数组也不是对象 ===> 将原数据返回出来就是一种数据的拷贝
return data
}
// 遍历原数据
for (let key in data) {
if (typeof data[key] === 'object') { // 判断其中包含的数据的类型是否是数组或对象
// 调用递归函数,处理包含的数组或对象,得到一个新的数据,放在最终返回的数据中
newData[key] = deepCopy(data[key])
} else {
// 遍历出来的是一个基本数据,就直接放在最终返回的数据中
newData[key] = data[key]
}
}
// 将最终返回的数据返回出去
return newData
}
1488

被折叠的 条评论
为什么被折叠?



