FumadocsZDecode
JavaScript

数据类型

一、两大类

JavaScript 数据类型分为两大类:

  • 原始类型(Primitive):值存在栈上,赋值是值拷贝,共 7 种
  • 引用类型(Reference):值存在堆上,变量保存的是指针,赋值是引用拷贝

二、原始类型

类型示例typeof 返回
string'hello''string'
number42NaNInfinity'number'
booleantruefalse'boolean'
undefinedundefined'undefined'
nullnull'object' ← bug
symbolSymbol('id')'symbol'
bigint9007199254740991n'bigint'

原始值不可变——"修改"实际上是重新绑定变量:

let str = 'hello'
str[0] = 'H'     // 静默失败
console.log(str) // 'hello'
str = 'Hello'    // 这是重新赋值,不是修改原值

三、引用类型

本质都是 Object,内置的常用子类型:

类型创建方式说明
Object{}new Object()普通键值对
Array[]new Array()有序列表,下标从 0 开始
Functionfunction(){}() => {}可调用的对象,有 prototype
Datenew Date()时间对象
RegExp/pattern/new RegExp()正则表达式
Mapnew Map()任意键的键值对
Setnew Set()不重复值的集合
WeakMapnew WeakMap()弱引用 Map,键必须是对象
WeakSetnew WeakSet()弱引用 Set,值必须是对象
Errornew Error('msg')错误对象
typeof []          // 'object'
typeof {}          // 'object'
typeof function(){} // 'function'  ← 特例,函数有自己的 typeof 返回值
typeof new Date()  // 'object'

四、赋值行为对比

// 原始类型:值拷贝,互不影响
let a = 1
let b = a
b = 2
console.log(a) // 1

// 引用类型:引用拷贝,共享同一对象
let obj1 = { x: 1 }
let obj2 = obj1
obj2.x = 2
console.log(obj1.x) // 2

// 浅拷贝:新对象,但嵌套引用仍共享
let obj3 = { ...obj1 }
obj3.x = 99
console.log(obj1.x) // 2,不影响

let obj4 = { nested: { y: 1 } }
let obj5 = { ...obj4 }
obj5.nested.y = 99
console.log(obj4.nested.y) // 99,嵌套仍共享

五、包装对象

原始类型没有方法,JS 引擎访问属性时会临时包装成对应对象,用完即丢。

'hello'.toUpperCase() // 'HELLO'
// 内部等价于:new String('hello').toUpperCase()
原始类型包装构造函数
stringString
numberNumber
booleanBoolean

不要用 new 创建包装对象

typeof new String('hi') // 'object',不是 'string'
new Boolean(false) == true // true,对象始终 truthy

六、null 和 undefined

// undefined:声明了但未赋值
let x
console.log(x) // undefined

// null:主动表示"空值"
let y = null

null == undefined  // true(宽松相等的特殊规则)
null === undefined // false(类型不同)

typeof null        // 'object'  ← 历史 bug,不会修

约定null 表示"有意为空",undefined 表示"尚未初始化"。


七、number 特殊值

NaN === NaN          // false,NaN 不等于自身
Number.isNaN(NaN)    // true(正确用法)
isNaN('hello')       // true(有坑,会先转换)
Number.isNaN('hello')// false(不转换,更安全)

1 / 0                // Infinity
-1 / 0               // -Infinity
isFinite(Infinity)   // false

// 浮点精度
0.1 + 0.2 === 0.3    // false
0.1 + 0.2            // 0.30000000000000004

// 安全整数范围 ±2^53 - 1
Number.MAX_SAFE_INTEGER  // 9007199254740991
Number.isSafeInteger(9007199254740992) // false

八、BigInt

超出 Number 安全范围时用 BigInt,字面量加 n 后缀。

9007199254740991n + 1n  // 9007199254740992n,精确

// 不能与 number 直接混用
1n + 1   // TypeError
1n + 1n  // 2n
Number(1n) // 1  ← 手动转换

九、Symbol

每次调用产生唯一值,常用于对象私有键,避免命名冲突。

const id = Symbol('id')
const id2 = Symbol('id')
id === id2 // false

const obj = { [id]: 123 }
Object.keys(obj)    // [],Symbol 不出现在普通枚举中
obj[id]             // 123

// 全局共享
Symbol.for('key') === Symbol.for('key') // true

十、Map 和 Set vs 对象和数组

Map vs Object

const map = new Map()
map.set(1, 'number key')     // 键可以是任意类型
map.set({}, 'object key')
map.size                      // 2,直接获取长度

const obj = {}
obj[1] = 'key'               // 键会转为字符串
Object.keys(obj)             // ['1']

Set vs Array

const set = new Set([1, 2, 2, 3])
set.size   // 3,自动去重

// 数组去重常用手法
const arr = [...new Set([1, 2, 2, 3])] // [1, 2, 3]

WeakMap / WeakSet:键/值对目标对象不持强引用,对象被 GC 后自动清除,适合存储附加元数据而不阻止垃圾回收。

const cache = new WeakMap()
let dom = document.querySelector('#app')
cache.set(dom, { count: 0 })  // dom 销毁后,cache 里的条目自动消失

On this page