数据类型与运算

66 阅读5分钟

以下是JavaScript数据类型的详细归纳:

原始类型 (Primitive Types)

String (字符串)

  • 类型分类: 原始类型
  • 存储位置: 栈内存
  • 可变性: 不可变
  • 默认值: "" (空字符串)
  • 比较方式: 值比较
  • 关键特性: 创建后无法修改,任何修改都会创建新字符串

Number (数字)

  • 类型分类: 原始类型
  • 存储位置: 栈内存
  • 可变性: 不可变
  • 默认值: 0
  • 比较方式: 值比较
  • 关键特性: 包含整数、浮点数、NaN、Infinity

Boolean (布尔)

  • 类型分类: 原始类型
  • 存储位置: 栈内存
  • 可变性: 不可变
  • 默认值: false
  • 比较方式: 值比较
  • 关键特性: 只有两个值:true和false

null

  • 类型分类: 原始类型
  • 存储位置: 栈内存
  • 可变性: 不可变
  • 默认值: null
  • 比较方式: 值比较
  • 关键特性: 表示空值,typeof返回"object"(历史遗留问题)

undefined

  • 类型分类: 原始类型
  • 存储位置: 栈内存
  • 可变性: 不可变
  • 默认值: undefined
  • 比较方式: 值比较
  • 关键特性: 变量声明但未赋值时的默认值

Symbol (符号)

  • 类型分类: 原始类型
  • 存储位置: 栈内存
  • 可变性: 不可变
  • 默认值: 无默认值
  • 比较方式: 值比较(每个Symbol都是唯一的)
  • 关键特性: ES6新增,用于创建唯一标识符

BigInt (大整数)

  • 类型分类: 原始类型
  • 存储位置: 栈内存
  • 可变性: 不可变
  • 默认值: 无默认值
  • 比较方式: 值比较
  • 关键特性: ES2020新增,用于表示任意精度的整数

引用类型 (Reference Types)

Object (对象)

  • 类型分类: 引用类型
  • 存储位置: 堆内存,栈中存储引用地址
  • 可变性: 可变
  • 默认值: null{}
  • 比较方式: 引用比较
  • 关键特性: 键值对集合,所有引用类型的基类

Array (数组)

  • 类型分类: 引用类型(Object的特殊形式)
  • 存储位置: 堆内存,栈中存储引用地址
  • 可变性: 可变
  • 默认值: []
  • 比较方式: 引用比较
  • 关键特性: 有序的元素集合,有length属性

Function (函数)

  • 类型分类: 引用类型
  • 存储位置: 堆内存,栈中存储引用地址
  • 可变性: 可变
  • 默认值: null
  • 比较方式: 引用比较
  • 关键特性: 可执行对象,有一等公民地位

Date (日期)

  • 类型分类: 引用类型
  • 存储位置: 堆内存,栈中存储引用地址
  • 可变性: 可变
  • 默认值: null
  • 比较方式: 引用比较
  • 关键特性: 表示日期和时间的内置对象

RegExp (正则表达式)

  • 类型分类: 引用类型
  • 存储位置: 堆内存,栈中存储引用地址
  • 可变性: 可变
  • 默认值: null
  • 比较方式: 引用比较
  • 关键特性: 用于模式匹配的正则表达式对象

Map

  • 类型分类: 引用类型
  • 存储位置: 堆内存,栈中存储引用地址
  • 可变性: 可变
  • 默认值: null
  • 比较方式: 引用比较
  • 关键特性: 键值对集合,键可以是任意类型

Set

  • 类型分类: 引用类型
  • 存储位置: 堆内存,栈中存储引用地址
  • 可变性: 可变
  • 默认值: null
  • 比较方式: 引用比较
  • 关键特性: 值唯一的集合

WeakMap

  • 类型分类: 引用类型
  • 存储位置: 堆内存,栈中存储引用地址
  • 可变性: 可变
  • 默认值: null
  • 比较方式: 引用比较
  • 关键特性: 键必须是对象,弱引用,不影响垃圾回收

WeakSet

  • 类型分类: 引用类型
  • 存储位置: 堆内存,栈中存储引用地址
  • 可变性: 可变
  • 默认值: null
  • 比较方式: 引用比较
  • 关键特性: 值必须是对象,弱引用,不影响垃圾回收

总结对比

特性原始类型引用类型
存储位置栈内存堆内存(值)+栈内存(引用)
可变性不可变可变
比较方式值比较引用比较
复制行为深拷贝浅拷贝(复制引用)
内存管理自动回收通过引用计数和垃圾回收

一、JavaScript 数据类型概览

数据类型
├── 原始类型 (Primitive Types)
│   ├── String (字符串)
│   ├── Number (数字)
│   ├── Boolean (布尔)
│   ├── null
│   ├── undefined
│   ├── Symbol (符号)
│   └── BigInt (大整数)
└── 引用类型 (Reference Types)
    ├── Object (对象)
    ├── Array (数组)
    ├── Function (函数)
    ├── Date (日期)
    ├── RegExp (正则表达式)
    ├── Map
    ├── Set
    ├── WeakMap
    └── WeakSet

二、原始类型详解

1. String (字符串)

  • 表示文本数据
  • 创建方式:
    let str1 = "双引号"
    let str2 = '单引号'
    let str3 = `模板字符串${变量}`
    

2. Number (数字)

  • 表示整数和浮点数
  • 特殊值:
    • Infinity / -Infinity
    • NaN (Not a Number)
  • 示例:
    let num1 = 42
    let num2 = 3.14
    let num3 = Infinity
    

3. Boolean (布尔)

  • 逻辑值:truefalse
  • 示例:
    let isTrue = true
    let isFalse = false
    

4. null 和 undefined

  • null: 表示空值或不存在的对象
  • undefined: 变量已声明但未赋值
  • 示例:
    let empty = null
    let notDefined
    console.log(notDefined) // undefined
    

5. Symbol (符号)

  • ES6新增,唯一且不可变
  • 示例:
    let sym1 = Symbol('id')
    let sym2 = Symbol('id')
    console.log(sym1 === sym2) // false
    

6. BigInt

  • ES2020新增,任意精度整数
  • 示例:
    let bigNum = 123456789012345678901234567890n
    

三、引用类型详解

1. Object (对象)

let person = {
  name: "张三",
  age: 30,
  city: "北京"
}

2. Array (数组)

let fruits = ["苹果", "香蕉", "橙子"]
console.log(fruits[0]) // "苹果"

3. Function (函数)

function greet(name) {
  return `Hello, ${name}!`
}

4. 其他引用类型

  • Date: new Date()
  • RegExp: /abc/
  • Map/Set: new Map(), new Set()
  • WeakMap/WeakSet: new WeakMap()

四、类型判断方法

1. typeof 运算符

返回一个字符串,表示未经计算的操作数的类型。

typeof "hello""string"
typeof 42"number"
typeof true"boolean"
typeof undefined"undefined"
typeof null"object"    // 注意!
typeof Symbol()       → "symbol"
typeof 123n"bigint"
typeof {}             → "object"
typeof []             → "object"    // 注意!
typeof function(){}   → "function"

注意:typeof null 返回 "object" 是JavaScript的一个已知错误。why?

2. instanceof 运算符

检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

[] instanceof Array      // true
{} instanceof Object     // true
function(){} instanceof Function  // true

3. Object.prototype.toString.call()

最准确的类型判断方法,返回格式为 [object Type] 的字符串。

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

五、类型转换

1. 隐式转换规则

在某些操作中,JavaScript会自动进行类型转换。

  • 字符串拼接:
    "5" + 1      // "51"
    "5" + true   // "5true"
    
  • 数学运算:
    "5" - 2      // 3
    "5" * "2"    // 10
    true + 1     // 2
    
  • 比较运算:
    "5" == 5     // true (宽松相等)
    "5" === 5    // false (严格相等)
    

2. 显式转换方法

  • 转字符串:
    String(123)        // "123"
    (123).toString()   // "123"
    
  • 转数字:
    Number("123")      // 123
    parseInt("123")    // 123
    parseFloat("12.34") // 12.34
    +"123"             // 123
    
  • 转布尔值:
    Boolean(0)         // false
    Boolean("")        // false
    Boolean(null)      // false
    Boolean(undefined) // false
    Boolean(NaN)       // false
    Boolean(1)         // true
    Boolean("hello")   // true
    

六、重要注意事项

  1. 原始类型 vs 引用类型

    • 原始类型:存储在栈内存,按值访问
    • 引用类型:存储在堆内存,按引用访问
  2. 类型判断陷阱

    • typeof null 返回 "object"
    • typeof [] 返回 "object"
    • 使用 Array.isArray() 判断数组
  3. 相等比较

    • 推荐使用 ===!== 避免隐式转换
  4. 布尔转换假值

    • false, 0, "", null, undefined, NaN
建议使用严格相等(===)避免隐式转换带来的意外结果。
在if条件中,JavaScript会自动进行布尔转换。