JavaScript 数据类型完全指南

JavaScript 数据类型完全指南

数据类型是 JavaScript 的基础,也是每个开发者必须掌握的核心概念。本文将系统介绍 JS 的数据类型,包含代码示例、常用方法和高频面试题,帮助你建立完整的知识体系。

前言

JavaScript 是一门弱类型语言,但这并不意味着我们可以忽视类型的重要性。理解数据类型不仅能帮助我们写出更健壮的代码,还能在面试中游刃有余。本文将从基础到进阶,全面解析 JS 数据类型。

一、基本数据类型(Primitive Types)

基本数据类型是 JavaScript 中最基础的数据单元,它们的特点是不可变------一旦创建,值就固定了,想改只能重新赋值。这些类型直接存储在栈内存中,访问速度快。

1. String 字符串

字符串用于表示文本数据,可以使用单引号、双引号或反引号声明。

js 复制代码
// 声明方式
const str1 = '单引号字符串'
const str2 = "双引号字符串"
const str3 = `模板字符串,支持变量插值:${str1}`

// 常用方法
const text = 'Hello World'

console.log(text.length)           // 11 - 获取长度
console.log(text.toUpperCase())    // 'HELLO WORLD' - 转大写
console.log(text.toLowerCase())    // 'hello world' - 转小写
console.log(text.includes('World')) // true - 包含检查
console.log(text.startsWith('Hello')) // true - 开头检查
console.log(text.endsWith('World'))   // true - 结尾检查
console.log(text.split(' '))        // ['Hello', 'World'] - 分割
console.log(text.substring(0, 5))   // 'Hello' - 截取
console.log(text.replace('World', 'JS')) // 'Hello JS' - 替换
console.log(text.trim())            // 去除首尾空格

注意:模板字符串(反引号)支持变量插值,是现代 JavaScript 的推荐写法。

2. Number 数字

JavaScript 只有一种数字类型,包含整数和浮点数。还有特殊值 Infinity-InfinityNaN

js 复制代码
// 声明方式
const num1 = 42              // 整数
const num2 = 3.14            // 浮点数
const num3 = 1e6             // 科学计数法,等于 1000000

// 特殊值
console.log(Infinity)   // 正无穷
console.log(-Infinity)  // 负无穷
console.log(NaN)        // Not a Number
console.log(0 / 0)      // NaN

// 常用方法
const price = 123.456

console.log(price.toFixed(2))     // '123.46' - 保留小数位
console.log(Math.floor(price))    // 123 - 向下取整
console.log(Math.ceil(price))     // 124 - 向上取整
console.log(Math.round(price))    // 123 - 四舍五入
console.log(Math.max(1, 5, 3))    // 5 - 最大值
console.log(Math.min(1, 5, 3))    // 1 - 最小值
console.log(Math.random())        // 0-1 之间的随机数
console.log(parseInt('123abc'))   // 123 - 转整数
console.log(parseFloat('3.14'))   // 3.14 - 转浮点数
console.log(Number('123'))        // 123 - 转数字

3. Boolean 布尔值

布尔值只有两个值:truefalse,用于逻辑判断。

js 复制代码
// 声明方式
const isActive = true
const isDone = false

// 常见的 falsy 值(会被转为 false)
// false, 0, '', null, undefined, NaN

// 逻辑运算
console.log(true && false)  // false - 与
console.log(true || false)  // true - 或
console.log(!true)          // false - 非

4. Undefined 未定义

变量声明但未赋值时的默认值。

js 复制代码
let a  // 声明了,但没赋值
console.log(a)           // undefined
console.log(typeof a)    // 'undefined'

// 函数无返回值时也是 undefined
function noReturn() {}
console.log(noReturn())  // undefined

5. Null 空值

表示"无"、"空"或"未知"的值,是开发者主动声明的值。

js 复制代码
const emptyValue = null
console.log(typeof emptyValue)  // 'object' (历史遗留问题)

// 清空对象引用
let obj = { name: 'test' }
obj = null  // 清除引用,便于垃圾回收

6. Symbol (ES6)

创建唯一标识符,主要用于对象属性名。

js 复制代码
// 声明方式
const sym1 = Symbol('description')
const sym2 = Symbol('description')
console.log(sym1 === sym2)  // false - 每次都是唯一的

// 作为对象属性名
const obj = {
  [sym1]: '私有数据',
  name: '公开数据'
}

console.log(obj[sym1])  // '私有数据'
console.log(Object.keys(obj))  // ['name'] - 不包含 Symbol 属性

// 常用方法
const sym = Symbol('test')
console.log(sym.toString())      // 'Symbol(test)'
console.log(sym.description)     // 'test' - 获取描述

7. BigInt (ES2020)

表示大于 2^53 - 1 的整数。

js 复制代码
// 声明方式
const big1 = 9007199254740991n  // n 后缀
const big2 = BigInt(9007199254740991)

// 超大整数运算
const maxSafe = Number.MAX_SAFE_INTEGER  // 9007199254740991
console.log(maxSafe + 1)        // 9007199254740992 (精度丢失)
console.log(big1 + 1n)          // 9007199254740992n (正确)

// 不能与普通数字混用
// console.log(big1 + 1)  // TypeError
console.log(big1 + BigInt(1))   // 正确

// 常用场景
const bigNum = 123456789012345678901234567890n
console.log(bigNum.toString())  // 转字符串

二、引用数据类型(Object Types)

引用数据类型存储的是内存地址的引用。与基本类型不同,引用类型是可变的。

1. Object 对象

键值对的集合,最常用的引用类型。

js 复制代码
// 声明方式
const obj1 = {}
const obj2 = new Object()
const obj3 = { name: 'Alice', age: 25 }

// 常用操作
const person = {
  name: 'Bob',
  age: 30,
  sayHello: function() {
    return `Hello, I'm ${this.name}`
  }
}

// 访问属性
console.log(person.name)        // 'Bob'
console.log(person['age'])      // 30

// 添加/修改属性
person.job = 'Developer'
person['age'] = 31

// 删除属性
delete person.job

// 常用方法
console.log(Object.keys(person))      // ['name', 'age'] - 获取键名
console.log(Object.values(person))    // ['Bob', 30] - 获取键值
console.log(Object.entries(person))   // [['name', 'Bob'], ['age', 30]] - 键值对
console.log(Object.assign({}, person)) // 浅拷贝
console.log({...person})              // 扩展运算符浅拷贝
console.log(JSON.stringify(person))   // 转 JSON 字符串
console.log(JSON.parse('{"name":"Bob"}')) // JSON 转对象

2. Array 数组

有序的值的集合。

js 复制代码
// 声明方式
const arr1 = [1, 2, 3]
const arr2 = new Array(1, 2, 3)

// 常用方法
const fruits = ['apple', 'banana', 'orange']

// 访问和修改
console.log(fruits[0])      // 'apple'
fruits[1] = 'grape'         // 修改

// 增删元素
fruits.push('mango')        // 末尾添加
fruits.pop()                // 末尾删除
fruits.unshift('pear')      // 开头添加
fruits.shift()              // 开头删除
fruits.splice(1, 1)         // 从索引1删除1个元素

// 遍历和转换
fruits.forEach((item, index) => console.log(index, item))
const upper = fruits.map(f => f.toUpperCase())  // 映射
const filtered = fruits.filter(f => f.length > 5) // 过滤
const found = fruits.find(f => f === 'apple')    // 查找
const some = fruits.some(f => f.length > 5)      // 是否有满足条件的

// 其他常用
console.log(fruits.includes('apple'))  // true
console.log(fruits.join('-'))          // 'apple-banana-orange'
console.log(fruits.slice(1, 3))        // ['banana', 'orange']
console.log([...fruits].reverse())     // 反转
console.log([...fruits].sort())        // 排序

3. Function 函数

可执行的代码块,也是对象。

js 复制代码
// 声明方式
function func1() { return 1 }
const func2 = () => 2
const func3 = new Function('return 3')

// 函数属性
func1.name      // 函数名
func1.length    // 参数个数

// 高阶函数
const multiplier = (x) => (y) => x * y
const double = multiplier(2)
console.log(double(5))  // 10

// 立即执行函数
(function() {
  console.log('立即执行')
})()

4. Date 日期

处理日期和时间。

js 复制代码
const now = new Date()
const specific = new Date('2024-01-15')
const timestamp = new Date(1705315200000)

// 常用方法
console.log(now.getFullYear())    // 年
console.log(now.getMonth())       // 月 (0-11)
console.log(now.getDate())        // 日
console.log(now.getHours())       // 时
console.log(now.getMinutes())     // 分
console.log(now.getSeconds())     // 秒
console.log(now.getTime())        // 时间戳
console.log(now.toISOString())    // ISO 格式字符串
console.log(now.toLocaleString()) // 本地化字符串

5. RegExp 正则表达式

用于模式匹配。

js 复制代码
const pattern1 = /abc/i  // 字面量
const pattern2 = new RegExp('abc', 'i')

// 常用方法
const text = 'Hello 123 World'

console.log(pattern1.test(text))      // true - 测试匹配
console.log(text.match(/\d+/))        // ['123'] - 提取匹配
console.log(text.replace(/\d+/g, 'X')) // 'Hello X World' - 替换
console.log(text.split(/\s+/))        // ['Hello', '123', 'World'] - 分割

6. Map 和 Set (ES6)

Map: 键值对集合,键可以是任意类型。

js 复制代码
const map = new Map()

// 增删改查
map.set('key1', 'value1')
map.set(123, 'number key')
map.set({id: 1}, 'object key')

console.log(map.get('key1'))    // 'value1'
console.log(map.has('key1'))    // true
map.delete('key1')
console.log(map.size)           // 2

// 遍历
map.forEach((value, key) => console.log(key, value))
for (const [key, value] of map) {
  console.log(key, value)
}

Set: 唯一值的集合。

js 复制代码
const set = new Set([1, 2, 2, 3, 3])
console.log(set)  // Set(3) {1, 2, 3}

// 操作
set.add(4)
set.delete(2)
console.log(set.has(1))  // true
console.log(set.size)    // 3

// 数组去重
const arr = [1, 2, 2, 3, 3, 4]
const unique = [...new Set(arr)]  // [1, 2, 3, 4]

三、类型判断方法

typeof 操作符

js 复制代码
// 基本类型
console.log(typeof 'hello')      // 'string'
console.log(typeof 42)           // 'number'
console.log(typeof true)         // 'boolean'
console.log(typeof undefined)    // 'undefined'
console.log(typeof Symbol())     // 'symbol'
console.log(typeof 123n)         // 'bigint'

// 引用类型(注意)
console.log(typeof null)         // 'object' (历史遗留)
console.log(typeof {})           // 'object'
console.log(typeof [])           // 'object'
console.log(typeof function(){}) // 'function'
console.log(typeof new Date())   // 'object'

instanceof 操作符

js 复制代码
console.log([] instanceof Array)           // true
console.log({} instanceof Object)          // true
console.log(new Date() instanceof Date)    // true
console.log(/abc/ instanceof RegExp)       // true

// 无法判断基本类型
console.log('hello' instanceof String)     // false
console.log(42 instanceof Number)          // false

Array.isArray() 判断是否为数组

js 复制代码
console.log(Array.isArray([]))             // true
console.log(Array.isArray({}))             // false
console.log(Array.isArray('[]'))           // false

Object.prototype.toString.call()

最准确的类型判断方法:

js 复制代码
console.log(Object.prototype.toString.call('hello'))  // '[object String]'
console.log(Object.prototype.toString.call(42))       // '[object Number]'
console.log(Object.prototype.toString.call(true))     // '[object Boolean]'
console.log(Object.prototype.toString.call(null))     // '[object Null]'
console.log(Object.prototype.toString.call(undefined))// '[object Undefined]'
console.log(Object.prototype.toString.call([]))       // '[object Array]'
console.log(Object.prototype.toString.call({}))       // '[object Object]'
console.log(Object.prototype.toString.call(new Date()))// '[object Date]'

四、高频面试题

1. 基本类型 vs 引用类型的区别

答案

  • 存储位置:基本类型存储在栈内存,引用类型存储在堆内存(栈内存存储引用地址)
  • 赋值行为:基本类型赋值是复制值,引用类型赋值是复制引用地址
  • 比较方式:基本类型比较值,引用类型比较引用地址
  • 不可变性:基本类型不可变,引用类型可变
js 复制代码
// 基本类型
let a = 10
let b = a
b = 20
console.log(a)  // 10 (不变)

// 引用类型
let arr1 = [1, 2, 3]
let arr2 = arr1
arr2.push(4)
console.log(arr1)  // [1, 2, 3, 4] (一起变)

2. 判断数组的正确方法

答案Array.isArray() 是最可靠的方法

js 复制代码
// 推荐
Array.isArray([])

// 不推荐
[] instanceof Array  // 跨 iframe 有问题
Object.prototype.toString.call([]) === '[object Array]'  // 太繁琐

3. null 和 undefined 的区别

答案

  • undefined 表示"未定义",是变量的默认值

  • null 表示"空值",是主动赋值的值

  • 两者都是 falsy 值

  • typeof null 是 'object'(历史遗留问题)

4. 0.1 + 0.2 !== 0.3 的原因

答案:JavaScript 使用 IEEE 754 标准存储浮点数,存在精度问题

js 复制代码
console.log(0.1 + 0.2)  // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3)  // false

// 解决方案
console.log((0.1 + 0.2).toFixed(1))  // '0.3'
console.log(Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON)  // true
// EPSILON 是 ES6 的一种安全最小值,如果两数相差小于此值,则说明是正确的

5. Symbol 的用途

答案

  • 创建唯一标识符,避免属性名冲突
  • 实现私有属性(Symbol 属性不会被常规方法遍历)
  • 用于元编程(如 Symbol.iterator)
js 复制代码
const sym1 = Symbol('key')
const sym2 = Symbol('key')
console.log(sym1 === sym2)  // false

const obj = {
  [sym1]: '私有数据',
  name: '公开数据'
}
console.log(Object.keys(obj))  // ['name'] - Symbol 不会被遍历

6. BigInt 的使用场景

答案:处理超出 Number 安全范围的整数

js 复制代码
// Number 最大安全整数
const max = Number.MAX_SAFE_INTEGER  // 9007199254740991

// BigInt 可以处理更大
const big = 9007199254740991n
console.log(big + 1n)  // 正确

// 常用于金融计算、ID 生成等

7. Map 和 Object 的区别

答案

特性 Object Map
键的类型 只能是 String/Symbol 任意类型
顺序 ES6 后保持插入顺序 保持插入顺序
大小 需手动计算 .size 属性
性能 频繁增删性能较差 频繁增删性能更好
迭代 需用 Object.keys() 可直接迭代
js 复制代码
const obj = {}
const map = new Map()

// Object 的键只能是字符串
obj[1] = 'one'
obj['1'] = 'one'  // 覆盖上面的值

// Map 可以保持类型
map.set(1, 'one')
map.set('1', 'two')
console.log(map.size)  // 2

8. 类型转换陷阱

答案

js 复制代码
// 隐式类型转换
console.log('5' + 1)      // '51' (字符串拼接)
console.log('5' - 1)      // 4 (数学运算)
console.log([] + {})      // '[object Object]'
console.log({} + [])      // '[object Object]'

// 比较陷阱
console.log(0 == '0')     // true
console.log(0 === '0')    // false
console.log(null == undefined)  // true
console.log(null === undefined) // false

// 建议始终使用 === 进行比较

9. 如何判断一个值是否为 NaN

答案

js 复制代码
// 错误方法
console.log(NaN === NaN)  // false

// 正确方法
console.log(Number.isNaN(NaN))        // true
console.log(Object.is(NaN, NaN))      // true
console.log(typeof NaN === 'number')  // true

// 注意区别
console.log(Number.isNaN('abc'))      // false
console.log(isNaN('abc'))             // true (会先转换为数字)

10. 基本类型包装对象

答案:基本类型在调用方法时会临时包装成对象

js 复制代码
const str = 'hello'
console.log(str.length)  // 5
console.log(str.toUpperCase())  // 'HELLO'

// 等价于
const temp = new String('hello')
console.log(temp.length)
console.log(temp.toUpperCase())
// 但 temp 会被销毁

// 但不能给基本类型添加属性
str.customProp = 'test'
console.log(str.customProp)  // undefined (不会报错,但无效)

五、总结

数据类型速查表

类型 typeof 说明 可变性
String string 字符串 不可变
Number number 数字 不可变
Boolean boolean 布尔值 不可变
Undefined undefined 未定义 不可变
Null object 空值 不可变
Symbol symbol 唯一标识 不可变
BigInt bigint 大整数 不可变
Object object 对象 可变
Array object 数组 可变
Function function 函数 可变
Date object 日期 可变
RegExp object 正则 不可变
Map object 映射 可变
Set object 集合 可变

最佳实践

  1. 始终使用 const 声明变量,除非需要重新赋值
  2. 使用 === 进行严格比较,避免类型转换陷阱
  3. 使用 Array.isArray() 判断数组
  4. 处理浮点数时注意精度问题
  5. 使用 Map 替代 Object 当需要任意类型键时
  6. 使用 BigInt 处理超大整数
  7. 理解引用类型和基本类型的区别,避免意外的副作用

数据类型是 JavaScript 的基础,掌握它们对于编写高质量代码至关重要。希望本文能帮助你建立完整的知识体系。

相关推荐
代码猎人2 小时前
map和Object有什么区别
前端
Snack2 小时前
border-radius带来的锯齿问题
前端
代码猎人2 小时前
Set、Map有什么区别
前端
ETA82 小时前
不再是切图仔,router拯救了前端工程师
前端·react.js
发现一只大呆瓜2 小时前
JS-深度起底JS类型判断:typeof、instanceof 与 toString
javascript
毕设源码-朱学姐2 小时前
【开题答辩全过程】以 基于web网络投票系统平台的设计与实现为例,包含答辩的问题和答案
前端
萌狼蓝天2 小时前
[Vue]Tab关闭后,再次使用这个组件时,上次填写的内容依旧显示(路由复用导致组件实例未被销毁)
前端·javascript·vue.js·前端框架·ecmascript
皮坨解解2 小时前
关于领域模型的总结
前端
UIUV2 小时前
React+Zustand实战学习笔记:从基础状态管理到项目实战
前端·react.js·typescript