JavaScript类型检查的完整指南
JavaScript的动态类型是其最强大的特性之一。然而,对于经验不足的开发人员来说,它经常是问题和困惑的根源。因此,类型检查是任何JavaScript开发人员的关键技能。
值类型
在我们深入探讨JavaScript中不同的类型检查方式之前,让我们先看一下我们在JavaScript中可能遇到的不同值类型。
类型 | 描述 | 示例 |
---|---|---|
undefined |
尚未分配值的变量的值。 | let x; |
null |
任何对象值的有意缺失。 | const x = null; |
boolean |
逻辑值,要么是true ,要么是false 。 |
const x = true; |
number |
数值。 | const x = 50; |
bigint |
具有任意精度的整数。 | const x = 9007199254740991n; |
string |
字符串序列。 | const x = 'Hello!'; |
symbol |
可用作对象属性键的唯一值。 | const x = Symbol(); |
object |
属性的集合。 | const x = { a: 1, b: 2 }; |
function |
可调用的对象。 | const x = () => {}; |
除了最后两种类型,所有其他类型都被视为原始类型。原始类型是不可变的,这意味着它们的值不能被改变。而对象和函数则是可变的,这意味着它们的值可以被改变。
检查原始类型
与对象和函数相比,原始类型通常更容易进行类型检查。这是因为原始类型是不可变的,这意味着它们的值不能被改变。因此,我们可以简单地将一个值的类型与我们要检查的类型进行比较。这就是typeof
运算符派上用场的地方。
值是undefined
检查undefined
值就像将该值与undefined
进行比较一样简单。这与使用typeof
运算符得到的结果完全相同。
const isUndefined = val => val === undefined;
isUndefined(undefined); // true
值为null
检查null
值只能通过将值与null
本身进行比较。这是因为typeof null
返回'object'
,这不是我们想要的。
const isNull = val => val === null;
isNull(null); // true
值为nil
在其他一些语言中,使用nil
值来表示缺少值。然而,在JavaScript中,null
和undefined
用于此目的。因此,检查nil
值与检查null
或undefined
值是相同的。
const isNil = val => val === undefined || val === null;
isNil(null); // true
isNil(undefined); // true
isNil(''); // false
值是布尔类型
布尔值只能是true
或false
。检查这两个值相对低效,所以通常更倾向于使用typeof
。
const isBoolean = val => typeof val === 'boolean';
isBoolean(true); // true
isBoolean(false); // true
isBoolean('true'); // false
isBoolean(null); // false
值是数字类型
数字也可以使用typeof
进行类型检查。然而,这也会对NaN
返回true
,NaN
是一个特殊的数值,表示无法产生正常结果的操作的结果。
你可以阅读更多关于NaN
以及为什么它可能很棘手,但通常建议使用Number.isNaN()
来额外检查NaN
。
const isNumber = val => typeof val === 'number' && !Number.isNaN(val);
isNumber(1); // true
isNumber('1'); // false
isNumber(NaN); // false
值是大整数类型
BigInt是JavaScript中相对较新的添加。它们是具有任意精度的整数。使用typeof
对BigInt进行类型检查。
const isBigInt = val => typeof val === 'bigint';
isBigInt(1n); // true
isBigInt(1); // false
值是字符串
像大多数其他原始类型一样,字符串原始类型可以使用typeof
进行类型检查。
const isString = val => typeof val === 'string';
isString('Hello!'); // true
isString(1); // false
值是符号
符号是可以用作对象属性键的唯一值。它们也可以使用typeof
进行类型检查。
const isSymbol = val => typeof val === 'symbol';
isSymbol(Symbol('x')); // true
isSymbol('x'); // false
值是原始类型
检查一个值是否是任何原始类型有点棘手。我们不能简单地使用typeof
来判断,因为它对null
不起作用。
相反,我们可以从值创建一个对象,然后将其与值本身进行比较。如果值是原始类型,对象将不等于值。
const isPrimitive = val => Object(val) !== val;
isPrimitive(null); // true
isPrimitive(undefined); // true
isPrimitive(50); // true
isPrimitive('Hello!'); // true
isPrimitive(false); // true
isPrimitive(Symbol()); // true
isPrimitive([]); // false
isPrimitive({}); // false
检查非原始类型
对象和函数的行为与原始类型略有不同。虽然typeof
可以帮助我们一部分,但我们可能还想使用其他方法,特别是对于对象。
值是对象
如前所述,typeof
对于null
返回'object'
。这不是我们想要的,当我们检查对象时。相反,我们可以使用Object
构造函数为给定的值创建一个对象包装器。如果值是null
或undefined
,返回的值将是一个空对象。否则,返回的对象将与输入对象相同。
const isObject = obj => obj === Object(obj);
isObject([1, 2, 3, 4]); // true
isObject([]); // true
isObject(['Hello!']); // true
isObject({ a: 1 }); // true
isObject({}); // true
isObject(true); // false
isObject(null); // false
isObject(undefined); // false
[!TIP]
在JavaScript中,数组也被视为对象。建议使用
Array.isArray()
来检查一个值是否为数组。
值是函数
幸运的是,函数并不像对象那样棘手。我们可以简单地使用typeof
来检查一个值是否为函数。
const isFunction = val => typeof val === 'function';
isFunction(x => x); // true
isFunction('x'); // false
[!NOTE]
在JavaScript中,类也被视为函数。您可能希望使用
instanceof
运算符来检查一个值是否为类的实例。
值是异步函数
使用async
关键字声明的函数被视为异步函数。对于异步函数的类型检查,需要使用Object.prototype.toString()
和Function.prototype.call()
来检查结果是否为'[object AsyncFunction]'
。
const isAsyncFunction = val =>
Object.prototype.toString.call(val) === '[object AsyncFunction]';
isAsyncFunction(function() {}); // false
isAsyncFunction(async function() {}); // true
值是生成器函数
生成器函数可以像异步函数一样进行类型检查。它们的预期值是'[object GeneratorFunction]'
。
const isGeneratorFunction = val =>
Object.prototype.toString.call(val) === '[object GeneratorFunction]';
isGeneratorFunction(function() {}); // false
isGeneratorFunction(function*() {}); // true
值的类型
如果其他方法都失败了,或者你正在使用类和其他自定义类型,你可能想要获取一个值的类型的字符串表示。可以使用Object.prototype.constructor
和Function.prototype.name
来实现。
const getType = v =>
v === undefined ? 'undefined' : v === null ? 'null' : v.constructor.name;
getType(undefined); // 'undefined'
getType(null); // 'null'
getType(true); // 'Boolean'
getType(1); // 'Number'
getType(1n); // 'BigInt'
getType('Hello!'); // 'String'
getType(Symbol()); // 'Symbol'
getType([]); // 'Array'
getType({}); // 'Object'
getType(() => {}); // 'Function'
getType(new Set([1, 2, 3])); // 'Set'
检查值的类型
将前面的代码片段反过来,我们也可以检查一个值是否是特定类型。与之前一样,对于undefined
和null
需要特别注意,因为它们没有constructor
属性。
const isOfType = (type, val) =>
([undefined, null].includes(val) && val === type) ||
val.constructor.name === type;
isOfType(undefined, undefined); // true
isOfType(null, null); // true
isOfType('Boolean', true); // true
isOfType('Number', 1); // true
isOfType('BigInt', 1n); // true
isOfType('String', 'Hello!'); // true
isOfType('Symbol', Symbol()); // true
isOfType('Array', []); // true
isOfType('Object', {}); // true
isOfType('Function', () => {}); // true
isOfType('Set', new Set([1, 2, 3])); // true