主题
JavaScript 数据类型详解
温馨提示:本内容整理自阅读 《JavaScript 权威指南(第 7 版)》 和社区大神文章。
JavaScript 的数据类型分为:基本数据类型 和 引用数据类型。
基本数据类型(原始类型)
在 ES2020 标准中,共有 7 种基本类型:
undefined
:未定义null
:空指针boolean
:布尔值string
:字符串number
:数值symbol
:独一无二的值(ES6 引入)bigint
:大整数(ES2020 引入)
特性总结
- 保存原始值,无属性和方法
- 存储在 栈内存
- 通过 按值访问
- 复制时创建副本,新旧值之间互不影响
原始值竟然不报错?
js
const str = 'hello world'
str.toString()
str.length
其实是 JavaScript 内部做了包装处理:等价于
js
const str = 'hello world'
new String(str).toString()
new String(str).length
背后执行了:
- 创建对应包装类实例(如
String
) - 调用方法/属性
- 销毁临时对象
引用数据类型
除了基本类型,其他的都是引用类型:
Object
:普通对象Array
:数组Function
:函数Date
:时间对象RegExp
:正则表达式Set
/WeakSet
(ES6)Map
/WeakMap
(ES6)
特性总结
- 保存对象地址(引用),本体在堆内存
- 通过 按引用访问
- 复制的是地址(多个变量指向同一个对象)
栈内存 vs 堆内存
类型 | 描述 |
---|---|
栈内存 | 存储变量和地址,内存空间连续,速度快 |
堆内存 | 存储引用对象和闭包变量,内存不连续 |
延伸阅读:JS 中的栈内存和堆内存
类型判断方式(五种)
1. typeof
js
typeof undefined // 'undefined'
typeof null // 'object'
typeof true // 'boolean'
typeof 'hi' // 'string'
typeof 123 // 'number'
typeof Symbol() // 'symbol'
typeof BigInt(10) // 'bigint'
为什么 typeof null === 'object'
?
null
本是空指针(0x00),JS 最初实现中对象的类型标签是 0,因此错误地识别为 object
—— MDN 解释
引用类型结果:
js
typeof {} // 'object'
typeof [] // 'object'
typeof () => {} // 'function'
2. instanceof
判断某对象是否是某构造函数的实例(原型链上是否存在)
js
const arr = []
arr instanceof Array // true
arr instanceof Object // true
'hi' instanceof String // false
true instanceof Boolean // false
改变原型影响判断:
js
function Person(name) {
this.name = name
}
const p = new Person('Tom')
Reflect.setPrototypeOf(p, Array.prototype)
p instanceof Person // false
p instanceof Array // true
结论:
- 仅适合判断引用类型
- 构造函数原型被改动后判断结果不准确
3. constructor
使用 .constructor
判断构造函数:
js
(true).constructor === Boolean // true
'hi'.constructor === String // true
(123).constructor === Number // true
({}).constructor === Object // true
[].constructor === Array // true
js
function Person() {}
Person.prototype = {}
(new Person()).constructor === Object // true ❗️
结论:
- 不能判断
null
和undefined
- 构造函数原型被改动会导致错误
4. Array.isArray()
专用于判断是否为数组:
js
Array.isArray([]) // true
Array.isArray({}) // false
不需要考虑边界,推荐使用!
Object.prototype.toString
最强通用类型判断法:
js
const toString = Object.prototype.toString
toString.call(undefined) // '[object Undefined]'
toString.call(null) // '[object Null]'
toString.call(true) // '[object Boolean]'
toString.call('hi') // '[object String]'
toString.call(123) // '[object Number]'
toString.call(Symbol()) // '[object Symbol]'
toString.call(BigInt(10)) // '[object BigInt]'
toString.call([]) // '[object Array]'
toString.call({}) // '[object Object]'
toString.call(() => {}) // '[object Function]'
toString.call(new Date()) // '[object Date]'
Object.prototype.toString
在 ECMAScript 5 中的大致流程:
- 如果是
undefined
或null
,直接返回结果 - 将值转为对象
O = ToObject(this)
- 获取其内部
[[Class]]
- 返回格式为
[object Type]
总结
类型判断方法 | 优点 | 缺点 |
---|---|---|
typeof | 判断基本类型快 | 无法识别 null 和具体对象 |
instanceof | 判断引用类型有效 | 原型被改动就无效 |
constructor | 简洁 | 原型被重写时不准 |
Array.isArray() | 最好判断数组方式 | 仅限数组 |
Object.prototype.toString | 最准确通用 | 写法稍繁琐 |