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 str1 = Symbol('name'); const str2 = Symbol('name'); console.log(str1); //Symbol(name) console.log(str2); //Symbol(name) console.log(str1 === str2); //false
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。