js的值类型和引用类型
在ES6中js的数据类型分为两种,分别是值类型和引用类型。
- 常见的值类型:undefined,Boolean,number,String,symbol;
- 常见的引用类型:Object,Array,null(特殊的引用类型,指针指向空地址),function(特殊的引用类型,但没有存储数据,所以没有拷贝、复制函数这一说);
它们的区别
-
存储位置不同,值类型直接存储在栈中,而引用类型的值在堆中,并把存储地址存到栈中;
-
将一个值类型的变量赋值给另一个变量时,改变其中一个的值,另一个并不会发生改变;
let a = 2020 let b = a b = 2021 console.log(a) // 结果:2020 console.log(b) // 结果:2021
-
将一个引用类型的变量赋值给另一个变量时,只要改变了其中一个两个就都会发生改变;
const a = { name: '小明', age: 15 } const b = a b.age = 20 console.log(a.age) // 结果:20 console.log(b.age) // 结果:20
typeof运算符
说到数据类型就不得不说一下typeof运算符,它可以用来判断js变量的类型,那么它能够判断哪些类型呢?
-
能够识别所有值类型
-
能够判断是否是引用类型(不可再细分,会把Array也认为是object)
-
能够识别出函数
也就是说typeof运算符能够识别出7种类型,分别是:undefined,Boolean,number,String,symbol,object,functionlet a console.log(typeof a) // 结果: undefined const b = 100 console.log(typeof b) // 结果: number const c = '小明' console.log(typeof c) // 结果: string const d = { name: '小红' } console.log(typeof d) // 结果: object const e = ['a', 'b'] console.log(typeof e) // 结果: object const f = Symbol('foo') console.log(typeof f) // 结果: symbol
深拷贝和浅拷贝
在上面讲值类型和引用类型的区别时,就提到了将一个值类型的变量赋值给另一个变量时,改变其中一个的值,另一个也会发生改变。这种叫做浅拷贝;
什么是浅拷贝?
浅拷贝就是将变量所指向的引用地址直接赋值给另外一个变量,也就是说他们访问的是同一份资源,所以两个变量会相互影响。
什么是深拷贝?
在大多数项目中,我们需要的是两个变量,并不会相互影响,所以需要用到深拷贝;
深拷贝会重新创建一个字段和值相同的新的数据,并把其引用地址放回给我们定义的变量。
function deepClone (obj) {
if (typeof obj != 'object' || obj == null) {
// 如果是值类型或者为 null
return obj;
}
let result;
// 判断是数组还是对象, 对应不同的初始化结果
if (obj instanceof Array) {
result = [];
} else {
result = {};
}
// 循环遍历对象的属性或者数组的元素,并进行递归深度拷贝
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key])
}
}
return result;
}
const testObj = {
name: '小明',
age: 10,
address: ['北京','上海'],
score: {
math: 89,
english: 91
}
}
const a2 = deepClone(testObj);
a2.score.math = 100
console.log('testObj的math',testObj.score.math) // 结果:testObj的math 89
console.log('a2的math',a2.score.math) // 结果:a2的math 100
我们发现在改变了第二个变量后第一个并没有发生变化。