技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTJS

JavaScript 数据类型——八种数据类型总结

所属馆藏
JavaScript
文件格式
Markdown
原始路径
JavaScript/26-JavaScript 数据类型——八种数据类型总结
本文目录13 个章节
  1. 一、JavaScript 的八种语言类型
  2. 二、Number
  3. 三、String
  4. 四、Boolean
  5. 五、Undefined
  6. 六、Null
  7. 七、Symbol
  8. 八、BigInt
  9. 九、Object
  10. 十、类型判断与相等比较
  11. 十一、原始值包装对象
  12. 十二、总结
  13. 参考资料与原文

JavaScript 数据类型——八种数据类型总结

Category(分类): JavaScript Status: 已整理(2026)

原文按八种类型逐项介绍 Number、String、Boolean、Undefined、Null、Symbol、BigInt 和 Object。本文保留这个顺序,修正被复制按钮混入代码的数字、转义字符和示例结果,并把“基本类型/引用类型”的常见说法与 ECMAScript 的正式术语区分开。

一、JavaScript 的八种语言类型

ECMAScript 规范定义八种 语言类型

原始值类型

  • Undefined:只有一个值 undefined
  • Null:只有一个值 null
  • Booleantruefalse
  • String:字符串值;
  • Symbol:唯一的符号值;
  • Number:双精度浮点数值,包含 NaN 和正/负 Infinity
  • BigInt:任意精度的整数值。

对象类型

  • Object:对象值,包括普通对象、数组、函数、日期、正则表达式、Map、Set 和宿主对象等。

“基本数据类型”和“引用数据类型”是教材中常用的说法。更准确的表述是:前七种是原始值类型,最后一种是对象类型;函数是可调用的对象,数组也是对象。原始值本身不可变,但保存原始值的变量可以重新赋值;对象通常可变,但可以通过 Object.freeze()、代理或约定限制修改。

let value = 'old'
value = 'new' // 变量重新绑定,不是修改字符串本身

const object = { count: 1 }
object.count = 2 // 对象属性默认可修改

二、Number

Number 使用 IEEE 754 binary64 双精度格式表示数值。它可以表示整数和小数,也支持十进制、二进制、八进制和十六进制字面量:

const integer = 666
const decimal = 6.66
const binary = 0b1010 // 10
const octal = 0o70 // 56
const hexadecimal = 0x1f // 31

console.log(integer, decimal, binary, octal, hexadecimal)

旧式的前导 0 八进制写法依赖非严格脚本的历史语义,在严格模式和现代代码中不要使用。用 0o 明确表达八进制,用 0b 表达二进制。

1. 浮点数与精度

十进制小数通常不能被二进制浮点格式精确表示,因此会出现:

const a = 0.1
const b = 0.2
console.log(a + b) // 0.30000000000000004
console.log(a + b === 0.3) // false

“最高精度是 17 位小数”不是可靠的规范表述。可表示的有效数字数量、相邻数值间距和误差会随数值大小变化;需要精确十进制金额时,不要只依靠 Number

常见处理方式如下:

const roundedText = (0.1 + 0.2).toFixed(1)
console.log(roundedText) // '0.3'
console.log(Number(roundedText)) // 0.3

// 金额可以使用最小货币单位的整数
const cents = 10 + 20
console.log(cents / 100) // 0.3

乘以 10 的幂再除回来只能在特定范围内减少误差,不能保证所有计算都精确。toFixed() 返回字符串,适合展示;展示国际化数字可以考虑 Intl.NumberFormat,高精度金融计算则应选择经过验证的十进制库或整数/BigInt 方案。

2. 数值范围与安全整数

Number 能表示的有限范围可通过 Number.MAX_VALUE 等常量了解,但“能表示”不等于“每个整数都能精确表示”。安全整数范围是:

console.log(Number.MIN_SAFE_INTEGER) // -9007199254740991
console.log(Number.MAX_SAFE_INTEGER) // 9007199254740991
console.log(Number.isSafeInteger(2 ** 53 - 1)) // true
console.log(Number.isSafeInteger(2 ** 53)) // false

超出有限范围会得到 Infinity-Infinity;超出安全整数范围则可能已经丢失整数精度:

console.log(9999999999999999) // 10000000000000000
console.log(Number.isFinite(1e309)) // false

3. NaNInfinity 与判断

NaN 仍属于 Number 类型,但表示“不是一个有效数值结果”。它不等于任何值,包括自身:

console.log(typeof NaN) // 'number'
console.log(NaN === NaN) // false
console.log(Number.isNaN(NaN)) // true
console.log(Number.isNaN('not a number')) // false

全局 isNaN() 会先进行数值转换,容易把类型错误隐藏起来:

console.log(isNaN('10')) // false:字符串被转换成 10
console.log(isNaN('blue')) // true
console.log(Number.isNaN('blue')) // false:不进行隐式转换

console.log(Number.isFinite(10)) // true
console.log(Number.isFinite('10')) // false

需要判断结果是不是非有限数时使用 Number.isFinite();需要判断真正的 NaN 时优先使用 Number.isNaN()

4. 数值转换

  • Number(value):按完整的 ECMAScript 数值转换规则转换;
  • parseInt(string, radix):从字符串开头解析整数,建议明确传入进制;
  • parseFloat(string):从字符串开头解析十进制浮点数。
console.log(Number('10.5')) // 10.5
console.log(parseInt('10px', 10)) // 10
console.log(parseFloat('10.5px')) // 10.5
console.log(Number('10px')) // NaN

parseInt('08') 在现代 JavaScript 中通常按十进制处理,但传入 10 可以明确表达意图。不要用 parseInt 代替任意字符串的严格数值校验。

三、String

字符串可以使用单引号、双引号或模板字面量:

const name1 = '小明'
const name2 = "小明"
const name3 = `小明`

console.log(name1 === name2 && name2 === name3) // true

字符串值不可变;调用 toUpperCase()slice() 等方法会返回新字符串,不会修改原字符串。JavaScript 字符串以 UTF-16 代码元表示,因此 .length 统计的是代码元数量,不一定是用户看到的字符数:

const text = 'A😀'
console.log(text.length) // 3:A 1 个代码元,😀 2 个代理项代码元
console.log([...text].length) // 2:按 Unicode 码点迭代
console.log(Array.from(text)) // ['A', '😀']

涉及用户可见字符、组合字符或复杂文字时,应根据产品需求使用 Intl.Segmenter 等工具,而不是只依赖 .length

1. 转义序列

常见转义序列包括:

写法含义
\n换行
\t制表符
\b退格符,不是普通空格
\r回车
\f换页
\\反斜杠
\'单引号
\"双引号
\`反引号
\xNN两位十六进制代码元
\uNNNN四位十六进制 Unicode 代码元
\u{1F600}Unicode 码点转义,需使用支持该语法的现代环境

原文的 \Xnn 写法不正确,标准写法是小写 \xNN\uNNNN\u{1F600} 这类转义表示代码元或码点,不应简单等同于完整 Unicode 字符。

2. 字符串转换

String(value) 可以转换所有 JavaScript 值,包括 nullundefinedvalue.toString() 需要先有一个非空值,并且可能被对象自定义覆盖:

console.log(String(null)) // 'null'
console.log(String(undefined)) // 'undefined'
console.log((123).toString()) // '123'

// null.toString() 会抛出 TypeError

3. 模板字面量

模板字面量支持换行和 ${} 插值。插值表达式会先按普通 JavaScript 规则求值,再转换成字符串:

const message = `你好,${name1}
今天是 ${2020 + 6} 年`
console.log(message)

如果要把不可信内容插入 HTML,模板字符串不会自动转义,必须使用安全的 DOM API 或可信的 HTML 清洗方案。

四、Boolean

Boolean 只有 truefalse 两个值。条件判断会把其他值转换为布尔语义。常见假值包括:

  • false
  • 0-00n
  • NaN
  • ''(空字符串);
  • null
  • undefined

数组、普通对象和包装对象即使内容为空,也是真值:

console.log(Boolean('false')) // true
console.log(Boolean([])) // true
console.log(Boolean({})) // true
console.log(Boolean(new Boolean(false))) // true:这是对象

const input = ''
if (!input) console.log('没有输入')

Boolean(value) 适合显式转换,!!value 是常见的简写。不要把 true1false0 当成相同类型;宽松相等 == 还会触发额外的类型转换。

五、Undefined

undefinedUndefined 类型的唯一值,常见于:

  • 声明变量但没有赋值;
  • 访问不存在的对象属性;
  • 函数没有显式返回值;
  • 缺少函数参数;
  • void 表达式的结果。
let pending
const object = {}

function noReturn() {}

console.log(pending) // undefined
console.log(object.missing) // undefined
console.log(noReturn()) // undefined
console.log(void 0) // undefined

let/const 声明但尚未执行初始化的变量处于暂时性死区(TDZ),不能把它简单说成“已经是 undefined”:

try {
  console.log(value)
  let value = 1
} catch (error) {
  console.log(error.name) // ReferenceError
}

对未声明标识符使用 typeof 是一个特殊安全例外:

var declared
console.log(typeof declared) // 'undefined'
console.log(typeof neverDeclared) // 'undefined'
// console.log(neverDeclared) // ReferenceError

六、Null

null 是有意表示“没有对象值”的原始值。typeof null 返回 'object' 是 JavaScript 早期遗留的历史行为,不表示 null 真的是对象:

const car = null
console.log(typeof car) // 'object',历史遗留行为
console.log(car === null) // true

判断可能为对象的值时,通常需要同时排除 null

function isObject(value) {
  return value !== null && typeof value === 'object'
}

console.log(isObject({})) // true
console.log(isObject(null)) // false

七、Symbol

Symbol() 创建原始 Symbol 值。即使描述相同,两个独立创建的 Symbol 也不相等:

const first = Symbol('id')
const second = Symbol('id')

console.log(first === second) // false
console.log(first.description) // 'id'
console.log(typeof first) // 'symbol'

Symbol 很适合用作对象属性键,减少与普通字符串键冲突:

const id = Symbol('id')
const user = {
  name: 'Ada',
  [id]: 42
}

console.log(user[id]) // 42
console.log(user.id) // undefined:点语法中的 id 是字符串
console.log(Object.keys(user)) // ['name']:不会列出 Symbol 键
console.log(Reflect.ownKeys(user)) // ['name', Symbol(id)]

1. 全局 Symbol 注册表

Symbol.for(key) 会在当前 Realm 的全局 Symbol 注册表中查找或创建值;它与 Symbol() 不同:

const first = Symbol.for('app.id')
const second = Symbol.for('app.id')

console.log(first === second) // true
console.log(Symbol.keyFor(first)) // 'app.id'
console.log(Symbol.keyFor(Symbol('app.id'))) // undefined

全局注册表不是跨 iframe、Worker 或进程的全局通信机制。Symbol 也不能被隐式转换成字符串:

const token = Symbol('token')
console.log(String(token)) // 'Symbol(token)'
// 'token: ' + token // TypeError

八、BigInt

BigInt 用于任意精度整数,字面量以 n 结尾,也可以调用 BigInt()

const small = 10n
const large = 9007199254740993n
const fromString = BigInt('0x1fffffffffffff')

console.log(small + 2n) // 12n
console.log(large) // 9007199254740993n
console.log(fromString) // 9007199254740991n

Number.MAX_SAFE_INTEGER 以内的整数可以被 Number 精确表示;更大的整数应根据需求改用 BigInt 或十进制方案。

1. 运算规则

BigInt 支持大多数整数算术运算,但不能和 Number 直接进行算术混合:

console.log(10n + 10n) // 20n
console.log(11n - 10n) // 1n
console.log(2n * 10n) // 20n
console.log(110n / 10n) // 11n
console.log(5n / 2n) // 2n:向零截断
console.log(2n ** 3n) // 8n
console.log(10n > 2) // true:关系比较可以混用

// 10n + 2 会抛出 TypeError

BigInt 不支持 Math 方法和一元加号。为了演示一元加号的限制,可以在运行时捕获错误,而不要把非法的 +10n 直接写进普通代码块:

try {
  BigInt('+10')
  console.log('字符串可以被转换为 BigInt')
} catch (error) {
  console.log(error.name)
}

BigInt 不能直接被 JSON.stringify() 序列化,传输前需要约定字符串、数字或自定义编码格式。转换为 Number 可能丢失精度:

const value = 9007199254740993n
console.log(Number(value)) // 9007199254740992,精度可能丢失
console.log(JSON.stringify({ value: value.toString() })) // {"value":"9007199254740993"}

九、Object

对象是属性键和值的集合,并带有原型、属性描述符等内部语义。属性键只能是字符串或 Symbol;数组、函数、日期、正则表达式、Map 和 Set 都是对象。

1. 创建对象

对象字面量通常最清晰;new Object() 仍然有效,但没有必要作为首选:

const person = {
  name: '小明',
  age: 20,
  5: true
}

console.log(person['5']) // true:数值属性键会转成字符串

Object.create(proto) 可以创建指定原型的对象:

const prototype = {
  greet() {
    return 'hello'
  }
}

const object = Object.create(prototype)
console.log(object.greet()) // hello
console.log(Object.getPrototypeOf(object) === prototype) // true

如果需要字典而不是普通对象,可以使用 Object.create(null),但它没有 toStringhasOwnProperty 等继承方法:

const dictionary = Object.create(null)
dictionary.name = 'Ada'
console.log(dictionary.name) // Ada
console.log(Object.getPrototypeOf(dictionary)) // null

2. 属性读取和动态键

点语法适合固定且合法的标识符属性名;变量键、包含空格的键和 Symbol 键应使用中括号:

const propertyName = 'name'
const user = { name: '小明' }

console.log(user.name) // 小明
console.log(user[propertyName]) // 小明
user['display name'] = '小明'

需要检查自有属性时,优先使用 Object.hasOwn();为了兼容旧环境,可以使用安全调用形式:

const object = Object.create({ inherited: true })
object.own = true

console.log('inherited' in object) // true:包含原型链
console.log(Object.hasOwn(object, 'inherited')) // false:只检查自有属性
console.log(Object.hasOwn(object, 'own')) // true

不要直接调用 object.hasOwnProperty() 来处理不可信对象,因为该方法可能被覆盖,也可能在 Object.create(null) 对象上不存在。

3. 常见对象操作

const user = { name: 'Ada' }

console.log(Object.keys(user)) // ['name']
console.log(Object.values(user)) // ['Ada']
console.log(Object.entries(user)) // [['name', 'Ada']]

const copy = { ...user } // 浅复制
const frozen = Object.freeze(copy) // 浅冻结
console.log(frozen.name) // Ada

对象展开、Object.assign() 和数组展开都主要是浅复制。嵌套对象仍然共享引用:

const original = { profile: { name: 'Ada' } }
const copy = { ...original }
copy.profile.name = 'Grace'
console.log(original.profile.name) // Grace

需要深复制时,可以根据数据类型和运行环境选择 structuredClone();它不复制函数、DOM 节点或任意原型行为,也可能无法处理某些宿主对象。不要把 JSON 序列化当作通用深复制方案。

十、类型判断与相等比较

typeof 适合判断大多数原始类型,但有两个常见例外:typeof null === 'object',函数返回 'function'(函数本质仍是对象值):

function describe(value) {
  if (value === null) return 'null'
  if (Array.isArray(value)) return 'array'
  return typeof value
}

console.log(describe(null)) // null
console.log(describe([])) // array
console.log(describe(() => {})) // function
console.log(describe(1n)) // bigint

常用判断方式:

  • value === null 判断 null
  • Array.isArray(value) 判断数组;
  • typeof value === 'object' && value !== null 判断普通对象范围;
  • Number.isNaN(value) 判断真正的 NaN
  • value instanceof Constructor 判断原型链关系,但跨 Realm 时需谨慎;
  • Object.prototype.toString.call(value) 可作为某些旧环境的补充,但不能替代对具体 API 的判断。

严格相等 === 通常不进行类型转换;Object.is()=== 的两个显著差别是能区分 -00,并把 NaN 视为自身相等:

console.log(1 === '1') // false
console.log(Object.is(NaN, NaN)) // true
console.log(Object.is(-0, 0)) // false
console.log(-0 === 0) // true

十一、原始值包装对象

读取原始字符串的属性时,JavaScript 会在需要时临时进行包装,因此可以调用方法;这不意味着应该主动使用 new String()new Number()new Boolean()

const primitive = 'hello'
const wrapper = new String('hello')

console.log(primitive.toUpperCase()) // HELLO
console.log(typeof primitive) // string
console.log(typeof wrapper) // object
console.log(Boolean(new Boolean(false))) // true

包装对象会带来类型判断和布尔转换陷阱。业务代码应优先使用原始值。

十二、总结

记忆八种类型可以先抓住这些关键点:

  1. undefinednull 都只有一个值,但含义和 typeof 行为不同;
  2. Number 是 binary64 浮点数,安全整数范围有限;
  3. NaN 不等于自身,优先使用 Number.isNaN()
  4. 字符串按 UTF-16 代码元存储,.length 不一定等于用户看到的字符数;
  5. Symbol 是唯一原始值,可作为不会与普通字符串冲突的属性键;
  6. BigInt 适合大整数,但不能和 Number 混合算术,除法向零截断;
  7. 数组和函数都是对象;所谓“引用类型”是教学简称;
  8. 类型判断要结合 typeofArray.isArrayObject.hasOwn 和具体 API,而不要只背一张表。

参考资料与原文

457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS