JS的数据类型有哪些
在js中数据类型分为两种:原始值和引用值。原始值有string、number、boolean、null、undefined、Symbol、BigInt等原始类型,引用值有Object引用类型,Date、Array、TypeArray等引用类型都是Object的实例。
在 JavaScript 中,原始值是不可变的——一旦创建了原始值,它就不能被改变,尽管持有它的变量可以被重新分配另一个值。相比之下,对象和数组默认是可变的——它们的属性和元素可以在不重新分配新值的情况下更改。
由于以下几个原因,使用不可变的对象可能是有益的:
- 提高性能(不计划将来更改对象)
- 为了减少内存使用(进行对象引用 (en-US),而不是克隆整个对象)
- 线程安全(多个线程可以引用同一对象,而不会相互干扰)
- 降低开发人员的精神负担(对象的状态不会改变,其行为始终是一致的)
注意,你可以很容易证明可变性:只要对象提供一种方式来更改其属性,它就是可变的。另一方面,如果没有语言语义来保护它,就很难证明不可变性——这是一个开发人员约定俗成的问题。例如,Object.freeze() 是一种语言层面的方法,用于使对象在 JavaScript 中不可变。
如何区分JS的数据类型
除了 null之外,所有原始类型都可以使用 typeof 运算符测试。typeof null 返回 "object",因此必须使用 === null 来测试 null。
引用值可以使用instanceof操作符判断,所有引用值都是Object的实例,因此通过instanceof操作符检测任何引用值和Object构造函数都会返回true。如果用instanceof检测原始值,则始终会返回false,因为原始值不是对象。
基于上面的知识点,可以整理一下判断的步骤:
- 使用
typeof操作符判断变量的类型,如果是string、number、boolean、undefined、Symbol、BigInt等数据类型,则直接返回数据类型的字符串。 - 如果数据类型判断是
object,则再判断变量使用恒等于null,如果是则返回字符串null; - 如果不恒等于
null则再使用instanceof操作符判断,依次判断Function、Date、Array、TypeArray、RegExp等引用类型字符串,如果是则返回对应的引用类型 - 如果不是则再次判断是否是
Object的实例,如果是返回字符串object,如果不是则返回字符串unknown。
代码实现:
function typeOf(param) {
const originalValue = typeof param;
if (!/object/i.test(originalValue)) {
return originalValue;
}
if (param === null) {
return 'null';
}
if (param instanceof Function) {
return 'function';
}
if (param instanceof Array) {
return 'array';
}
if (param instanceof Date) {
return 'date';
}
if (param instanceof RegExp) {
return 'regexp';
}
// 添加你需要判断的引用类型......
if (param instanceof Object) {
return 'object';
}
return 'unknown';
}
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
setName(name) {
this.name = name;
}
}
const var1 = '';
const var2 = 1;
const var3 = true;
const var4 = null;
const var5 = undefined;
const var6 = Symbol(1);
const var7 = 1n;
const var8 = () => {};
const var9 = [1, 2, 3];
const var10 = new Date();
const var11 = /var/i;
const var12 = {};
const var13 = new Person();
[
var1,
var2,
var3,
var4,
var5,
var6,
var7,
var8,
var9,
var10,
var11,
var12,
var13,
].forEach((item) => {
console.log(typeOf(item));
});
// 打印结果
// string
// number
// boolean
// null
// undefined
// symbol
// bigint
// function
// array
// date
// regexp
// object
// object
优化实现
在上面的代码中发现一个问题,对于引用值需要明确知道其引用类型才能进行判断,否则不能返回其引用类型字符串,是否可以不知道其引用类型但是依然可以返回其引用的字符串?
答案是可以的,使用Object.prototype.toString方法可以返回[object XXX]字符串,XXX就是数据类型。但是对于用户自定义的引用类型,Object.prototype.toString方法只会返回[object Object]字符串,而不是具体的引用类型,如果想要判断出具体的引用类型,可以参考Object.prototype.toString。
优化后的代码:
function typeOf(param) {
return Object.prototype.toString.call(param).slice(8, -1).toLowerCase();
}
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
setName(name) {
this.name = name;
}
toString() {
return 'person';
}
}
const var1 = '';
const var2 = 1;
const var3 = true;
const var4 = null;
const var5 = undefined;
const var6 = Symbol(1);
const var7 = 1n;
const var8 = () => {};
const var9 = [1, 2, 3];
const var10 = new Date();
const var11 = /var/i;
const var12 = {};
const var13 = new Person();
[
var1,
var2,
var3,
var4,
var5,
var6,
var7,
var8,
var9,
var10,
var11,
var12,
var13,
].forEach((item) => {
console.log(typeOf(item));
});
// 打印结果
// string
// number
// boolean
// null
// undefined
// symbol
// bigint
// function
// array
// date
// regexp
// object
// object
扩展知识
typeof null为什么是"object"?
null是一种基本数据类型,存储在栈区;Object是引用数据类型,存储在堆区。typeof null的结果是Object,但是null instanceof Object的结果是false,可以知道null并不是Object的实例,两者之间存在矛盾。
js在底层存储变量的时候,会在变量的机器码低位1~3位存储其类型信息:
| 机器码 | 类型信息 |
|---|---|
| 000 | 对象 |
| 010 | 浮点数 |
| 100 | 字符串 |
| 110 | 布尔值 |
| 1 | 整数 |
但对于undefined和null来说,这两个信息存储有些特殊的:
- null:所有的机器码都是0
- undefined:用-2^30整数表示
所以typof在判断null的时候就出现问题了,由于null所有机器均为0,因此直接被当做对象看待。