js数据类型分类及存储区别
1. js数据类型分类
js一共有8种数据类型,7种基本数据类型和1种引用数据类型。
7种基本数据类型:Undefined
、Null
、Boolean
、Number
、String
、Symbol
(es6
新增,表示独一无二的值)和BigInt
(es10
新增)。
Symbol
代表独一无二的值,最大的用法是用来定义对象的唯一属性名。BigInt
可以表示任意大小的整数。
需要注意的是,JS
中 的数字类型都是浮点类型的,没有整型。
1种引用数据类型:Object
(Object本质上是由一组无序的名值对组成的,包含普通对象-Object
,数组对象-Array
,正则对象-RegExp
,日期对象-Date
,数学函数-Math
,函数对象-Function
)。
1.1 什么是Symbol类型
ES6
之前的对象属性名都是字符串,这容易造成属性名的冲突。
比如说你引入一个同事写的 js
代码,你往他 js
代码里面一个很复杂的对象里面添加新的属性方法,如果是用属性名还是使用字符串的方式,你加的方法就有可能和你同事加的方法重名了。
const str1 = Symbol('name');
const str2 = Symbol('name');
console.log(str1); //Symbol(name)
console.log(str2); //Symbol(name)
console.log(str1 === str2); //false
即使是传入相同的参数,生成的Symbol值也是不相等的,因为Symbol本来就是独一无二的意思。
const obj={};
obj[Symbol('name')]='张三';
obj[Symbol('name')]='李四';
console.log(obj); //{Symbol(name): '张三', Symbol(name): '李四'}
ES6
引入 Symbol 类型让对象的属性名可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
1.2 什么是BigInt类型
- 什么是
BigInt
?
BigInt
是一种新的数据类型,用于当整数值大于Number数据类型支持的范围时。BigInt
只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。
这种数据类型允许我们安全地对大整数执行算术操作,表示高分辨率的时间戳,使用大整数id,等等,而不需要使用库。 - 为什么需要
BigInt
?
在JS
中,所有的数字都以双精度64位浮点格式表示,那这会带来什么问题呢?
这导致JS
中的Number无法精确表示非常大的整数,它会将非常大的整数四舍五入,确切地说,JS
中的Number
类型只能安全地表示(-2^53-1) 和 (2 ^53-1),任何超出此范围的整数值都可能失去精度。二是大于或等于2的1024次方的数值,JavaScript 无法表示,会返回Infinity
。
console.log(999999999999999); //=>10000000000000000
同时也会有一定的安全性问题:
9007199254740992 === 9007199254740993; // → true 居然是true!
- 如何创建并使用
BigInt
?
1.要创建BigInt
,只需要在数字末尾追加n
即可。
console.log( 9007199254740995n ); // → 9007199254740995n
console.log( 9007199254740995 ); // → 9007199254740996
2.另一种创建BigInt
的方法是用BigInt()
构造函数
BigInt("9007199254740995"); // → 9007199254740995n
简单使用如下:
10n + 20n; // → 30n
10n - 20n; // → -10n
+10n; // → TypeError: Cannot convert a BigInt value to a number BigInt不支持一元加号运算符
-10n; // → -10n
10n * 20n; // → 200n
20n / 10n; // → 2n
23n % 10n; // → 3n
10n ** 3n; // → 1000n
42n === 42 // false BigInt 与普通整数是两种值,它们之间并不相等
const x = 10n;
++x; // → 11n
--x; // → 9n
console.log(typeof x); //"bigint" typeof运算符对于 BigInt 类型的数据返回bigint
- 值得警惕的点
BigInt
不支持一元加号运算符, 因为会与asm.js
(一种提升js
执行效率的解决方案)冲突。
因为隐式类型转换可能丢失信息,所以不允许在bigint
和Number
之间进行混合操作。当混合使用大整数和浮点数时,结果值可能无法由BigInt
或Number
精确表示。
10 + 10n; // → TypeError
不能将BigInt
传递给Web api
和内置的 JS
函数,这些函数需要一个 Number 类型的数字。
Math.max(2n, 4n, 6n); // → TypeError
当 Boolean
类型与 BigInt
类型相遇时,BigInt
的处理方式与Number
类似,换句话说,只要不是0n
,BigInt
就被视为truthy
的值。
if(0n){//条件判断为false
}
if(3n){//条件为true
}
- 元素都为
BigInt
的数组可以进行sort。 BigInt
可以正常地进行位运算,如|
、&
、<<
、>>
和^
2. 存储方式差异
基本数据类型保存在栈里面,可以直接访问它的值;引用数据类型保存在堆里面,栈里面保存的是地址,通过栈里面的地址去访问堆里面的值。
赋值时,原始类型的赋值会完整复制变量值,两个对象对应不同的地址;而引用类型的赋值是复制引用地址,两个变量指向堆内存中同一个对象。
基本类型示例:
let a = 10;
let b = a; // 赋值操作
b = 20;
console.log(a); // 10值
a
的值为一个基本类型,是存储在栈中,将a
的值赋给b
,虽然两个变量的值相等,但是两个变量保存了两个不同的内存地址,所以b的改变不会引起a的变化。
下图是基本类型赋值过程
引用类型示例1:
var obj1 = {
}
var obj2 = obj1;
obj2.name = "xxx";
console.log(obj1.name); // xxx
obj1
是一个引用类型,在赋值操作过程汇总,实际是将堆内存对象在栈内存的引用地址复制了一份给了obj2
,实际上他们共同指向了同一个堆内存对象,所以更改obj2
会对obj1
产生影响。
下图是引用类型赋值过程
引用类型示例2:
function test(person) {
person.age = 26
person = {
name: 'hzj',
age: 18
}
return person
}
const p1 = {
name: 'fyq',
age: 19
}
const p2 = test(p1)
console.log(p1) // -> ?
console.log(p2) // -> ?
// 结果:
p1:{
name: “fyq”, age: 26}
p2:{
name: “hzj”, age: 18}
原因: 在函数传参的时候传递的是对象在堆中的内存地址值,test函数中的实参person是p1对象的内存地址,通过调用person.age = 26
确实改变了p1的值,但随后person
变成了另一块内存空间的地址,并且在最后将这另外一份内存空间的地址返回,赋给了p2。