数据类型(Data Types)

JavaScript 中的数据类型:原始类型与对象类型的使用和底层原理


📖 入门:基础使用

1. 数据类型分类

JavaScript 中的数据类型分为两大类:

1.1 原始类型(Primitive Types)

7 种原始类型

  1. number — 数字
  2. string — 字符串
  3. boolean — 布尔值
  4. undefined — 未定义
  5. null — 空值
  6. symbol — 符号(ES6)
  7. bigint — 大整数(ES2020)

特点

  • ✅ 值不可变(immutable)
  • ✅ 按值传递
  • ✅ 存储在栈内存中

示例

let num = 42;           // number
let str = "Hello";      // string
let bool = true;        // boolean
let undef = undefined;  // undefined
let nul = null;         // null
let sym = Symbol("id"); // symbol
let big = 9007199254740991n; // bigint

1.2 对象类型(Object Types)

对象类型

  • Object — 普通对象
  • Array — 数组
  • Function — 函数
  • Date — 日期
  • RegExp — 正则表达式
  • 等等…

特点

  • ✅ 值可变(mutable)
  • ✅ 按引用传递
  • ✅ 存储在堆内存中

示例

let obj = { name: "Alice" };  // Object
let arr = [1, 2, 3];          // Array
let func = function() {};     // Function

2. 类型判断

2.1 typeof 运算符

语法

typeof value

示例

typeof 42;          // "number"
typeof "hello";     // "string"
typeof true;        // "boolean"
typeof undefined;   // "undefined"
typeof null;        // "object" ⚠️(历史遗留问题)
typeof {};          // "object"
typeof [];          // "object"
typeof function(){}; // "function"

注意

  • typeof null 返回 "object"(这是 JavaScript 的历史遗留问题)
  • typeof 无法区分数组和对象

2.2 instanceof 运算符

语法

value instanceof Constructor

示例

[] instanceof Array;        // true
[] instanceof Object;       // true(数组也是对象)
{} instanceof Object;       // true
new Date() instanceof Date; // true

2.3 Object.prototype.toString()

更准确的类型判断

Object.prototype.toString.call(42);       // "[object Number]"
Object.prototype.toString.call("hello");  // "[object String]"
Object.prototype.toString.call(null);     // "[object Null]"
Object.prototype.toString.call([]);       // "[object Array]"
Object.prototype.toString.call({});       // "[object Object]"

3. 类型转换

3.1 显式类型转换

转换为字符串

String(123);        // "123"
(123).toString();   // "123"
String(null);       // "null"
String(undefined);  // "undefined"

转换为数字

Number("123");      // 123
Number("");         // 0
Number("abc");      // NaN
parseInt("123");    // 123
parseFloat("12.3"); // 12.3

转换为布尔值

Boolean(1);         // true
Boolean(0);         // false
Boolean("");        // false
Boolean("hello");   // true
Boolean(null);      // false
Boolean(undefined); // false

3.2 隐式类型转换

字符串拼接

"Hello" + 123;      // "Hello123"
123 + "456";        // "123456"

数学运算

"123" - 1;          // 122(字符串转数字)
"123" * 2;          // 246
"123" / 1;          // 123

布尔值转换

if (1) { }          // 1 转换为 true
if ("") { }         // "" 转换为 false
if (0) { }          // 0 转换为 false

🚀 提高:底层原理

1. 内存模型

1.1 栈内存(Stack)

原始类型存储

  • 原始类型的值直接存储在栈内存中
  • 访问速度快
  • 内存占用小

示例

let a = 10;
let b = a;  // 复制值
b = 20;
console.log(a);  // 10(a 的值不变)

内存布局

栈内存
├── a: 10
└── b: 20(独立的值)

1.2 堆内存(Heap)

对象类型存储

  • 对象存储在堆内存中
  • 变量存储的是对象的引用(地址)
  • 访问速度相对较慢
  • 内存占用较大

示例

let obj1 = { name: "Alice" };
let obj2 = obj1;  // 复制引用
obj2.name = "Bob";
console.log(obj1.name);  // "Bob"(obj1 和 obj2 指向同一个对象)

内存布局

栈内存          堆内存
├── obj1 ────┐
└── obj2 ────┘  └── { name: "Bob" }

2. 值传递 vs 引用传递

2.1 原始类型:值传递

原理

  • 传递的是值的副本
  • 修改不会影响原变量

示例

function change(x) {
  x = 100;  // 修改的是副本
}
 
let num = 10;
change(num);
console.log(num);  // 10(原值不变)

2.2 对象类型:引用传递

原理

  • 传递的是对象的引用(地址)
  • 修改会影响原对象

示例

function change(obj) {
  obj.name = "Bob";  // 修改的是原对象
}
 
let person = { name: "Alice" };
change(person);
console.log(person.name);  // "Bob"(原对象被修改)

3. 类型转换机制

3.1 抽象操作(Abstract Operations)

JavaScript 引擎使用抽象操作进行类型转换:

ToPrimitive

  • 将值转换为原始类型
  • 优先级:valueOf()toString()

ToNumber

  • 将值转换为数字
  • 规则复杂,涉及多种情况

ToString

  • 将值转换为字符串

ToBoolean

  • 将值转换为布尔值
  • 遵循”假值”(falsy)规则

3.2 类型转换规则

原始类型转换

// 转换为数字
Number("123");     // 123
Number("");        // 0
Number("abc");     // NaN
Number(true);      // 1
Number(false);     // 0
Number(null);      // 0
Number(undefined); // NaN
 
// 转换为字符串
String(123);       // "123"
String(true);      // "true"
String(null);      // "null"
String(undefined); // "undefined"
 
// 转换为布尔值
Boolean(0);        // false
Boolean("");       // false
Boolean(null);     // false
Boolean(undefined);// false
Boolean(NaN);      // false
// 其他值都是 true

对象类型转换

// 对象转原始类型
let obj = {
  valueOf() { return 42; },
  toString() { return "Object"; }
};
 
Number(obj);       // 42(先调用 valueOf)
String(obj);       // "Object"(先调用 toString)

4. 假值(Falsy Values)

JavaScript 中的假值

  • false
  • 0
  • ""(空字符串)
  • null
  • undefined
  • NaN

示例

if (!value) {
  // value 是假值时执行
}
 
// 真值(Truthy)检查
if (value) {
  // value 是真值时执行
}

5. nullundefined 的区别

undefined

  • 变量声明但未赋值
  • 函数参数未提供
  • 对象属性不存在
  • 函数没有返回值

null

  • 表示”空值”的明确赋值
  • 是一个对象引用
  • 需要显式赋值

示例

let a;           // undefined(未赋值)
let b = null;    // null(明确赋值)
 
// typeof 的区别
typeof undefined;  // "undefined"
typeof null;       // "object"(历史遗留)
 
// 相等性
undefined == null;  // true(相等)
undefined === null; // false(不全等)

📝 最佳实践

  1. 使用严格相等:使用 === 而不是 == 避免类型转换
  2. 明确类型判断:使用 Object.prototype.toString() 进行准确的类型判断
  3. 避免隐式转换:明确进行类型转换,避免依赖隐式转换
  4. 理解假值:清楚哪些值是假值,避免误判

🔗 相关链接


javascript 数据类型 类型转换 内存模型