咳咳,各位观众老爷们,晚上好!我是今天的主讲人,咱们今儿个唠唠 JavaScript 里 typeof
操作符对待 BigInt
和 Number
这俩兄弟的不同态度。准备好了吗?咱们这就开始!
引子:JavaScript 的数据类型江湖
话说这 JavaScript 江湖啊,数据类型林立,各门各派都有自己的绝活。其中,Number
和 BigInt
算是比较重要的两支流派。Number
掌管着常规的数字运算,精度有限,但用起来方便快捷。而 BigInt
则是一位后起之秀,专门解决超大整数的运算问题,精度那是杠杠的,但用法上稍微有些不同。
那么,typeof
这个行走江湖的“类型侦探”,是如何识别这两位呢?
正题:typeof
的“双标”行为
typeof
,顾名思义,就是用来判断一个变量或者表达式的类型的。它的返回值是一个字符串,表示被检测对象的类型。
- Number 门派:坦诚相待
对于 Number
类型的变量,typeof
的表现那是相当的坦诚。
let num = 42;
console.log(typeof num); // 输出 "number"
let floatNum = 3.14;
console.log(typeof floatNum); // 输出 "number"
let infinityNum = Infinity;
console.log(typeof infinityNum); // 输出 "number"
let nanNum = NaN;
console.log(typeof nanNum); // 输出 "number"
瞧见没?无论是整数、浮点数、无穷大,还是 NaN (Not a Number),typeof
都毫不犹豫地告诉你,它们都是 number
类型。
- BigInt 门派:另眼相看
但是,对于 BigInt
类型的变量,typeof
的态度就有点微妙了。
let bigIntNum = 42n;
console.log(typeof bigIntNum); // 输出 "bigint"
let anotherBigIntNum = 12345678901234567890n;
console.log(typeof anotherBigIntNum); // 输出 "bigint"
注意到了吗?typeof
并没有把 BigInt
归到 number
门下,而是单独给它颁发了一个 "bigint" 的称号。
为什么 typeof
要区别对待?
这就要从 BigInt
的诞生背景说起了。BigInt
的出现是为了解决 JavaScript 中 Number
类型无法精确表示过大的整数的问题。
Number
类型使用的是 IEEE 754 双精度浮点数格式,它可以精确表示的整数范围是 -2^53 到 2^53 – 1。一旦超出这个范围,就会出现精度丢失的问题。
console.log(Number.MAX_SAFE_INTEGER); // 输出 9007199254740991
console.log(Number.MAX_SAFE_INTEGER + 1); // 输出 9007199254740992
console.log(Number.MAX_SAFE_INTEGER + 2); // 输出 9007199254740992 (精度丢失!)
为了解决这个问题,ES2020 引入了 BigInt
类型,它可以表示任意精度的整数。
因为 BigInt
和 Number
在内部存储方式和运算规则上都有很大的不同,所以 typeof
将它们区分开来,也是为了避免混淆,让开发者能够更清楚地了解变量的类型。
typeof
的返回值有哪些?
为了更好地理解 typeof
的行为,我们来总结一下它的返回值类型。
类型 | typeof 返回值 |
示例 |
---|---|---|
Number | "number" | typeof 42; // "number" |
String | "string" | typeof "hello"; // "string" |
Boolean | "boolean" | typeof true; // "boolean" |
Undefined | "undefined" | typeof undefined; // "undefined" |
Null | "object" | typeof null; // "object" (历史遗留问题) |
Symbol | "symbol" | typeof Symbol("foo"); // "symbol" |
Object | "object" | typeof {}; // "object" |
Function | "function" | typeof function(){}; // "function" |
BigInt | "bigint" | typeof 42n; // "bigint" |
typeof
的注意事项
-
null
的特殊待遇:typeof null
返回 "object",这是一个历史遗留问题,是 JavaScript 最初的设计缺陷之一。在 JavaScript 的早期版本中,null
被认为是一个空对象指针,所以typeof
返回 "object"。虽然现在已经知道这是一个错误,但是为了保持向后兼容性,这个错误一直被保留了下来。 -
typeof
不适合判断数组类型:typeof []
和typeof {}
都会返回 "object",所以typeof
无法区分数组和普通对象。要判断一个变量是否是数组,可以使用Array.isArray()
方法。 -
函数也是对象: 在 JavaScript 中,函数也是一种特殊的对象,所以
typeof function(){}
返回 "function"。
BigInt
的使用场景
既然 BigInt
这么厉害,那它主要用在哪些场景呢?
-
处理超大整数: 这是
BigInt
最主要的应用场景,比如处理数据库中的 ID、加密算法中的密钥等等。 -
金融计算: 在金融领域,对精度要求非常高,使用
BigInt
可以避免精度丢失的问题。 -
科学计算: 在科学计算中,经常会遇到非常大的数字,使用
BigInt
可以保证计算的准确性。
BigInt
的限制
虽然 BigInt
功能强大,但也存在一些限制:
-
不能和
Number
类型直接进行运算:BigInt
只能和BigInt
类型的数字进行运算。如果需要和Number
类型的数字进行运算,需要先将Number
类型的数字转换为BigInt
类型。let bigIntNum = 42n; let numberNum = 10; // console.log(bigIntNum + numberNum); // 报错:TypeError: Cannot mix BigInt and other types, use explicit conversions console.log(bigIntNum + BigInt(numberNum)); // 正确:输出 52n
-
不能使用
Math
对象中的方法:Math
对象中的方法是为Number
类型设计的,不能直接用于BigInt
类型。let bigIntNum = 42n; // console.log(Math.sqrt(bigIntNum)); // 报错:TypeError: Cannot convert a BigInt value to a number
-
JSON 序列化:
BigInt
不能直接被 JSON 序列化。需要先将其转换为字符串。let bigIntNum = 42n; // JSON.stringify({ value: bigIntNum }); // 报错:TypeError: Do not know how to serialize a BigInt JSON.stringify({ value: bigIntNum.toString() }); // 正确:输出 {"value":"42"}
代码示例:比较 Number 和 BigInt
为了更直观地展示 Number
和 BigInt
的区别,我们来看几个代码示例。
// Number 的精度问题
let num1 = Number.MAX_SAFE_INTEGER;
let num2 = num1 + 1;
let num3 = num1 + 2;
console.log(num1); // 输出 9007199254740991
console.log(num2); // 输出 9007199254740992
console.log(num3); // 输出 9007199254740992 (精度丢失!)
// BigInt 的高精度
let bigIntNum1 = BigInt(Number.MAX_SAFE_INTEGER);
let bigIntNum2 = bigIntNum1 + 1n;
let bigIntNum3 = bigIntNum1 + 2n;
console.log(bigIntNum1); // 输出 9007199254740991n
console.log(bigIntNum2); // 输出 9007199254740992n
console.log(bigIntNum3); // 输出 9007199254740993n (精度正确!)
// BigInt 的运算
let a = 10n;
let b = 3n;
console.log(a + b); // 输出 13n
console.log(a - b); // 输出 7n
console.log(a * b); // 输出 30n
console.log(a / b); // 输出 3n (注意:BigInt 的除法会向下取整)
console.log(a % b); // 输出 1n
console.log(a ** b); // 输出 1000n
总结:typeof
的意义和价值
typeof
操作符在 JavaScript 中扮演着重要的角色,它可以帮助我们了解变量的类型,从而避免一些潜在的错误。虽然 typeof
对 null
的处理存在一些问题,但总体来说,它仍然是一个非常有用的工具。
特别是 BigInt
的引入,使得 typeof
能够更准确地反映 JavaScript 的数据类型体系。通过区分 Number
和 BigInt
,typeof
帮助开发者更好地理解和使用这两种类型,从而编写出更健壮、更可靠的代码。
特性 | Number | BigInt |
---|---|---|
精度 | 有限精度(IEEE 754 双精度浮点数) | 任意精度 |
类型 | number |
bigint |
运算 | 可以和 Number 类型直接进行运算 |
只能和 BigInt 类型进行运算,需要显式转换 |
Math 方法 |
可以使用 Math 对象中的方法 |
不能使用 Math 对象中的方法 |
JSON 序列化 | 可以直接序列化 | 需要先转换为字符串才能序列化 |
最后的彩蛋:类型判断的更多姿势
除了 typeof
之外,JavaScript 还提供了其他一些类型判断的方法,比如:
instanceof
:判断一个对象是否是某个类的实例。Object.prototype.toString.call()
:可以更精确地判断对象的类型。
这些方法各有优缺点,在实际开发中可以根据具体情况选择合适的方法。
好了,今天的讲座就到这里。希望大家对 typeof
操作符对待 BigInt
和 Number
的区别有了更深入的了解。感谢各位的观看,咱们下回再见! 记得点赞投币收藏哦!