JavaScript 中的数据类型详解

JavaScript 中的数据类型可以分为两大类:原始类型(基本类型) 和引用类型(对象类型)

一、核心概念:原始类型 vs 引用类型

在深入具体类型之前,理解这个区别至关重要。

特性原始类型 (Primitive Types)引用类型 (Reference Types)
存储方式值本身直接存储在栈内存值存储在堆内存中,栈内存中存储的是地址(指针)
比较方式比较的是是否相等比较的是内存地址是否相等(即是否是同一个对象)
可变性不可变,值本身无法被改变可变,可以随时添加、修改、删除属性
复制方式复制时会创建一个全新的值复制时只复制地址,多个变量指向同一个对象

二、原始类型 (Primitive Types)

ECMAScript 标准定义了 7 种原始数据类型:

1. undefined
  • 含义:表示变量已声明但未初始化,或函数没有明确返回值。

  • 特点

    • 一个变量只声明不赋值,它的默认值就是 undefined

    • 它是一个原始值,不是对象,没有方法。

  • 示例

    let a;
    console.log(a); // undefined
    console.log(typeof a); // "undefined"
    
    function foo() {}
    console.log(foo()); // undefined
2. null
  • 含义:表示一个空值对象指针为空。通常用于主动释放对象引用。

  • 特点

    • typeof null 返回 "object",这是一个历史悠久的 bug,无法修复(会破坏现有兼容性)。

    • 在逻辑运算中,null 被视为 falsy(假值)。

  • 示例

    let empty = null;
    console.log(empty); // null
    console.log(typeof empty); // "object" (注意这个坑!)
    
    // 判断一个值是否为 null 的正确方法
    console.log(empty === null); // true
3. boolean
  • 含义:逻辑值,只有两个:true 和 false

  • 特点

    • 常用于条件判断和循环控制。

    • 其他类型的值可以通过布尔转换变成布尔值。转换规则中,false0""nullundefinedNaN 会转为 false,其他所有值都转为 true

  • 示例

    let isActive = true;
    let isGreater = 10 > 5; // true
    
    // 布尔转换
    console.log(Boolean(0)); // false
    console.log(Boolean("hello")); // true
    console.log(!!"hello"); // true (!! 是快速转换为布尔值的技巧)
4. number
  • 含义:用于表示整数和浮点数(小数)。JavaScript 中所有数字都是基于 IEEE 754 标准的双精度 64 位二进制格式。

  • 特点

    • 整数和浮点数let count = 10; let price = 99.95;

    • 特殊值

      • NaN (Not-a-Number):一个特殊的值,表示一个本来要返回数值的操作失败了(如 0 / 0)。NaN 与任何值(包括自己)都不相等。使用 isNaN() 函数来判断。

      • Infinity 和 -Infinity:表示正负无穷大(如 1 / 0)。

    • 数值范围Number.MAX_VALUENumber.MIN_VALUE

    • 精度问题:由于二进制浮点数的限制,进行小数运算时可能会有精度误差(如 0.1 + 0.2 !== 0.3)。处理金融计算时建议使用 BigInt 或以分为单位存储,或使用第三方库。

  • 示例

    let num = 42;
    let pi = 3.14159;
    let result = 10 / 0; // Infinity
    let invalid = Math.sqrt(-1); // NaN
    
    console.log(isNaN(invalid)); // true
    console.log(0.1 + 0.2); // 0.30000000000000004
5. string
  • 含义:表示文本数据,由零个或多个 16 位 Unicode 字符组成。

  • 特点

    • 不可变:字符串一旦创建,其内容就不能改变。str[0] = 'X' 这样的操作是无效的。修改字符串实际上是创建了一个新的字符串。

    • 可以用单引号 (')、双引号 (") 或反引号 (`) 表示。

    • 使用反引号可以定义模板字符串,支持多行文本和字符串插值${expression})。

  • 示例

    let name = "Alice";
    let greeting = `Hello, ${name}!`; // Hello, Alice!
    let multiLine = `This is
    a multi-line
    string.`;
6. symbol (ES6 新增)
  • 含义:表示唯一不可变的值,主要用于对象的属性名,以确保属性名不会冲突。

  • 特点

    • 通过 Symbol() 函数创建,每次调用都会返回一个全新的、唯一的 Symbol。

    • 可以传入一个字符串作为描述,便于调试,但即使描述相同,Symbol 值也不同。

    • Symbol 作为属性名时,在 for...inObject.keys() 中不可枚举,需要使用 Object.getOwnPropertySymbols() 来获取。

  • 示例

    let sym1 = Symbol('id');
    let sym2 = Symbol('id');
    console.log(sym1 === sym2); // false
    
    let obj = {
      [sym1]: "secret value"
    };
    console.log(obj[sym1]); // "secret value"
7. bigint (ES2020 新增)
  • 含义:用于表示任意精度的整数,解决 number 类型无法安全表示大于 2^53 - 1 的整数的问题。

  • 特点

    • 通过在整数末尾加 n 来创建,或者调用 BigInt() 函数。

    • 不能和 number 类型直接进行混合数学运算,需要先显式转换。

  • 示例

    let bigNum = 9007199254740991n; // 最大的安全整数
    let evenBigger = bigNum + 1n;
    
    console.log(typeof bigNum); // "bigint"
    
    // 需要转换
    let regularNum = 100;
    console.log(bigNum + BigInt(regularNum)); // 9007199254741091n

三、引用类型 (Reference Types)

object

对象是属性的集合,属性是键值对(key-value pair)。键通常是字符串或 Symbol,值可以是任何类型,包括其他对象。

  • 创建方式

    • 字面量语法:let obj = { name: 'Bob', age: 25 };

    • 构造函数:let obj = new Object();

  • 常见内置对象

    • Array (数组):有序的数据集合。

      let fruits = ['Apple', 'Banana'];
      console.log(Array.isArray(fruits)); // true
    • Function (函数):函数也是对象,是一种可调用的对象。

      function sayHi() { console.log('Hi!'); }
      console.log(typeof sayHi); // "function" (但本质上它是对象的一种子类型)
    • Date (日期):处理日期和时间。

    • RegExp (正则表达式):用于模式匹配文本。

    • MapSetWeakMapWeakSet (ES6):更复杂的集合数据结构。

    • 以及其他许多内置对象,如 ErrorPromise 等。

引用类型的核心陷阱:复制与比较
// 1. 复制:只复制地址
let obj1 = { value: 10 };
let obj2 = obj1; // obj2 和 obj1 指向同一个对象
obj2.value = 20;
console.log(obj1.value); // 20 (!) 原对象也被修改了

// 2. 比较:比较的是地址,不是内容
let obj3 = { value: 20 };
let obj4 = { value: 20 };
console.log(obj3 == obj4); // false (!) 尽管内容相同,但它们是两个不同的对象
console.log(obj3 === obj4); // false

四、类型检测方法

  1. typeof 操作符

    • 用于检测原始类型(除 null 外)非常有效。

    • 对引用类型,除了 function 返回 "function",其他都返回 "object"

    typeof "hello" // "string"
    typeof 42      // "number"
    typeof true    // "boolean"
    typeof undefined // "undefined"
    typeof Symbol() // "symbol"
    typeof 10n     // "bigint"
    typeof null    // "object" (著名的bug)
    typeof {}      // "object"
    typeof []      // "object" (无法区分数组和普通对象)
    typeof function(){} // "function"
  2. instanceof 操作符

    • 用于检测一个对象是否是某个构造函数的实例。适用于检测具体的引用类型。

    • 原理:检查构造函数的 prototype 属性是否出现在对象的原型链上。

    [] instanceof Array; // true
    {} instanceof Object; // true
    new Date() instanceof Date; // true
    
    // 注意:所有引用类型的原型链末端都是 Object
    [] instanceof Object; // true
  3. Array.isArray()

    • 专门用于判断一个值是否为数组,比 instanceof 更可靠(尤其是在多个 frame 或 realm 中)。

  4. Object.prototype.toString.call()

    • 最强大、最准确的类型检测方法。可以准确返回 [object Type] 字符串。

    Object.prototype.toString.call(null); // "[object Null]"
    Object.prototype.toString.call([]); // "[object Array]"
    Object.prototype.toString.call({}); // "[object Object]"
    Object.prototype.toString.call(new Date()); // "[object Date]"

总结

类型分类可变性typeof 结果备注
undefined原始不可变"undefined"未定义
null原始不可变"object"空值(历史bug)
boolean原始不可变"boolean"布尔值
number原始不可变"number"数字(含浮点、NaN、Infinity)
string原始不可变"string"字符串
symbol原始不可变"symbol"唯一值(ES6)
bigint原始不可变"bigint"大整数(ES2020)
object引用可变"object"对象(包括Array, Date等)
function引用可变"function"函数(对象的一种)

理解这些数据类型的特性和区别,是编写健壮、高效 JavaScript 代码的基石。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值