JS-数据类型

43 阅读3分钟

前言

JavaScript 的类型系统是每个前端工程师的必经之路。为什么 [] == ![] 会返回 true?为什么 const 定义的对象可以修改属性?这一切的答案都藏在数据类型的底层存储与转换逻辑中。

一、 JS 数据类型全家桶

JavaScript 目前共有 8 种 内置类型,分为基本数据类型和引用数据类型。

1. 基本数据类型(Primitive)

  • String: 字符串。

  • Number: 数字(含整数、浮点数及 NaN)。

  • Boolean: 逻辑判断位 true / false

  • Undefined: 变量已声明但未赋值,或函数缺失参数。

  • Null: 表示“空对象”,常用于解除对象引用。

    注意:验证 null 必须使用全等 ===,因为 null == undefined 为 true。

  • BigInt (ES2020) : 安全存储任意精度的整数,解决 Number 超过 25312^{53}-1 精度丢失问题。

  • Symbol (ES6) : 表示独一无二的值,常用于对象属性私有化。

2. 引用数据类型(Reference)

  • Object: 包含 Array, Date, RegExp, Function 等。

二、 内存分配:栈与堆的艺术

基本类型与引用类型的本质区别在于存储位置

特性基本数据类型引用数据类型
存储位置栈 (Stack)堆 (Heap)
存储内容直接存储变量值存储指向堆内存的指针(地址)
访问机制直接访问值先取栈中地址,再跳转堆中取值
复制表现副本独立,互不影响复制地址,指向同一份数据(浅拷贝)

为什么要分栈和堆?

栈空间连续且小,查找极快;堆空间巨大且灵活。将大小固定的原始值放栈中、大小不定的对象放堆中,是性能与空间的平衡。


三、 显式类型转换(Explicit)

1. 转换为 String

  • toString(): 注意 nullundefined 调用此方法会报错。
  • 与空字符串 + '': 最简便的方法。

2. 转换为 Boolean

  • Boolean() 包装。
  • 使用双感叹号 !!: !!'hello' // true

3. 转换为 Number

  • Number() : null \rightarrow 0undefined \rightarrow NaNtrue \rightarrow 1
  • parseInt / parseFloat: 规则更严格,若首位不是数字,null/undefined/bool 均转为 NaN

四、 隐式类型转换:JS 的“黑盒”

隐式转换发生在编译器发现运算符两边数据类型不统一时。

1. 逻辑触发

  • 条件语句: if, while, for 中的表达式会被隐式转为 Boolean。
  • 逻辑运算符: &&, ||, ! 会触发转换。

2. 算术触发

  • 非加法运算: -, *, /, %, ++, -- 都会强制将操作数转为 Number

  • + 运算符(最复杂) :

    • 字符串拼接: 只要有一方是 String,另一方就会转为 String。
    • 数值计算: 若双方均为基本类型(且无 String),则转为 Number。

3. 对象转基本类型 (Object to Primitive)

当对象参与运算时,JS 内部会调用 Symbol.toPrimitivevalueOf()toString()

JavaScript

// 自定义对象转换逻辑
let obj = {
  [Symbol.toPrimitive](hint) {
    if (hint === 'number') return 10;
    if (hint === 'string') return 'hello';
    return true;
  }
};
console.log(+obj);     // 10 (hint 是 number)
console.log(`${obj}`); // "hello" (hint 是 string)

五、 总结与避坑指南

  1. 判断 null: 永远使用 v === null
  2. NaN 的特性: NaN !== NaN,判断 NaN 请使用 Number.isNaN()
  3. 引用拷贝: 修改引用类型的变量会影响所有指向该地址的变量,深拷贝(Deep Copy)是解决此问题的利器。